While react-hook-form
supports strong typing everywhere, including support for types inferred from a Yup schema (Yup.InferType<Schema>
), passing field names to controls is still untyped. However, this can be resolved with RHF's FieldPath
type and a helper function.
// Option 1: Declared per form, less boilerplate per control
export const getOrganizationFormField = (name: FieldPath<OrganizationForm>) => name;
getOrganizationFormField("billingAddress.address1");
// Option 2: Declared globally, more boilerplate per control
export const getFormField = <T extends FieldValues>(name: FieldPath<T>) => name;
getFormField<OrganizationForm>("billingAddress.address1");
// Option 3: Declared globally but extended per form, hybrid
export const getFormField = <T extends FieldValues>(name: FieldPath<T>) => name;
export const getOrganizationFormField = getFormField<OrganizationForm>;
getOrgFormField("billingAddress.address1");
// utils.ts
/**
* Support strongly typing RHF form field names (when using in UI, etc)
*
* @param name - Field names (strongly typed)
* @returns Typed field name
*
* @example
* const getTypedFormField = <T extends FieldValues>(name: FieldPath<T>) => name;
*
* type FormSchema = Yup.InferType<{ ... }>;
* const getFormField = getTypedFormField<FormSchema>;
*
* return <Input name={getFormField("strongly.typed")} />;
*/
export const getTypedFormField = <T extends FieldValues>(name: FieldPath<T>) => name;
// MemberForm.tsx
type OrganizationForm = Yup.InferType<{ ... }>;
// "Alias" the global function with the inferred type to reduce boilerplate
const getFormField = getTypedFormField<OrganizationForm>;
return <Input name={getFormField("strongly.typed.field")} />;