Using Typescript with React and useForm

108 views Asked by At

I am trying to factor out some repetitive code for a React form. I intend to add a label to the input returned from function Field and perhaps a few other doodads. I have been trying to use a proper type for the name parameter, but have not found one that works.

Here is the current error I get: Argument of type 'string' is not assignable to parameter of type '"name" | "details"'.ts(2345) (parameter) name: string

I have tried reinventing the wheel by defining the string union listed in the error, but that doesn't match either. I say "reinventing the wheel" because this form will eventually have many fields, and I'd rather list them only once.

Here is my code:

import { useForm } from 'react-hook-form';

function MyForm () {
    const { handleSubmit, register } = useForm<FormValues>();

    const onSubmit = handleSubmit ((data: FormValues) => {
        console.log({data});
    });

    function Field({name}: {name: string}) {
        console.log({name})
        return (
            <>
                <input {...register(name)} />
            </>
        );
    }
    
    return (
        <form onSubmit={onSubmit}>
            <Field name={"name"} />
            <input {...register("name")} placeholder="name" />
            <input {...register("details")} placeholder="details" />
            <input type="submit" />
        </form>
    );
}

type FormValues = {
    name: string;
    details: string;
}

export default MyForm;

I have tried defining the string union listed in the error, but that doesn't match either. I also tried registering the field name outside of the function and passing its result into the function.

1

There are 1 answers

1
Richard Zilahi On

You can utilize FieldPath generic from react-hook-form, to type the Field function.


import { useForm, FieldPath } from "react-hook-form";

function Field({ name }: { name: FieldPath<FormValues> }) {
    return <input {...register(name)} />;
}

and then this won't throw an error anymore:

<Field name="name" />

working example in codesandbox