I want to have a reusable uncontrolled Input component using react-hook-form, but I can't seem to get the types right.
Something like this:
CodeSandbox link with the example.
Obs.: The code seems to be running just fine. I think it's just a matter of adjusting the types.
// REUSABLE UNCONTROLLED INPUT
interface NoteInputValue extends FieldValues {
note: string;
}
type NoteInputProps = {
register: UseFormRegister<NoteInputValue>;
};
const NoteInput: React.FC<NoteInputProps> = (props) => {
const { register } = props;
return <input {...register("note")} />;
};
This is the form component:
// SOME FORM COMPONENT THAT NEEDS
// TO USE THE INPUT
interface FormValues extends FieldValues {
note: string;
someOtherField: boolean;
}
type MyFormProps = {};
const MyForm: React.FC<MyFormProps> = (props) => {
const { register } = useForm<FormValues>({
defaultValues: {
note: "",
someOtherField: true
}
});
return (
<>
<NoteInput register={register} />
</>
);
};
This is the TypeScript error I'm getting:
Just to have it documented here, I found two approaches that could work, but aren't ideal, imo.
My ultimate goal is to just pass the register function and it should be able to register the name of the input that it already has knowledge of, without receiving the name as props.
https://codesandbox.io/s/modest-brook-2yknnc
// REUSABLE UNCONTROLLED INPUT
interface InputValue {
note: string;
}
interface NoteInputProps<FormValues> {
register: UseFormRegister<FormValues>;
}
const NoteInput = <FormValues extends InputValue>(
props: NoteInputProps<FormValues>
) => {
const { register } = props;
// Note:
// Couldn't get rid of the `name` type assertion as Path<FormValues>.
// Even though `FormValues extends InputValue` (so it must
// have the `note` field). We get an error if we try to call
// register('note') without the type assertion
const name = "note" as Path<FormValues>;
return <input {...register(name)} />;
};
Or, passing the name explicitly (which was what I was trying to avoid):
https://codesandbox.io/s/objective-northcutt-9hb5t2?file=/src/App.tsx
// REUSABLE UNCONTROLLED INPUT
interface InputValue {
note: string;
}
interface NoteInputProps<FormValues> {
name: FieldPath<FormValues>;
register: UseFormRegister<FormValues>;
}
const NoteInput = <FormValues extends InputValue>(
props: NoteInputProps<FormValues>
) => {
const { name, register } = props;
return <input {...register(name)} />;
};