Reusable react-hook-form useFieldArray component in TypeScript

Viewed 576

I am making a reusable, dynamic form component using react-hook-form's useFieldArray hook and I am having problems correctly adding the type for field.

To set-up the form I have added a type and some defaultValues:

export type NamesArray = { name: string; required: boolean }[];

export type FormValues = { randomFormValue: string; namesArray: NamesArray };

const defaultValues = {
  namesArray: [{ name: "Me", required: true }]
};

Now, when I use my reusable form component, <NamesForm /> it should always know to use the namesArray part of the form for that component such that I should be able to do:

type Props<T> = {
  control: Control<T>;
  register: UseFormRegister<T>;
};

export function NamesForm<T extends NamesArray>({
  control,
  register
}: Props<T>) {
  const { fields, append } = useFieldArray<T, "namesArray", "id">({
    control,
    name: "namesArray"
  });

  return (
    <>
      {fields.map((field, index) => {
        return {field.required && <input {...register(`namesArray.${index}.name` as const)} />};
      })}

      <button type="button" onClick={() => append({})}>
        Append
      </button>
    </>
  );
}

Where, in order to make the component reusable, I have used generic props.

My problem is that even though I have explicitly said that my generic T should contain a namesArray, TS can't seem to pick that up and gives me the error:

Type 'string' does not satisfy the constraint 'ArrayPath'.

And it is not enough for me to not define the type of field because I would like to use field's properties such as required.

Code sandbox: https://codesandbox.io/s/controlled-field-array-forked-vooe9w?file=/src/NamesForm.tsx:139-214

0 Answers
Related