Skip to content

Typescript Support

List of exported Typescript Types.

Important: Typescript ^4.3 above is the recommended version to work with react hook form.

</> Resolver

import { useForm, Resolver } from "react-hook-form"
type FormValues = {
firstName: string
lastName: string
}
const resolver: Resolver<FormValues> = async (values) => {
return {
values: values.firstName ? values : {},
errors: !values.firstName
? {
firstName: {
type: "required",
message: "This is required.",
},
}
: {},
}
}
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({ resolver })
const onSubmit = handleSubmit((data) => console.log(data))
return (
<form onSubmit={onSubmit}>
<input {...register("firstName")} placeholder="Bill" />
{errors?.firstName && <p>{errors.firstName.message}</p>}
<input {...register("lastName")} placeholder="Luo" />
<input type="submit" />
</form>
)
}

</> SubmitHandler

import { useForm, SubmitHandler } from "react-hook-form"
type FormValues = {
firstName: string
lastName: string
email: string
}
export default function App() {
const { register, handleSubmit } = useForm<FormValues>()
const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input type="email" {...register("email")} />
<input type="submit" />
</form>
)
}

</> SubmitErrorHandler

import { useForm, SubmitHandler, SubmitErrorHandler } from "react-hook-form"
type FormValues = {
firstName: string
lastName: string
email: string
}
export default function App() {
const { register, handleSubmit } = useForm<FormValues>()
const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data)
const onError: SubmitErrorHandler<FormValues> = (errors) =>
console.log(errors)
return (
<form onSubmit={handleSubmit(onSubmit, onError)}>
<input {...register("firstName", { required: true })} />
<input {...register("lastName", { minLength: 2 })} />
<input type="email" {...register("email")} />
<input type="submit" />
</form>
)
}

</> FormSubmitHandler

The type for the Form component's onSubmit prop — unlike SubmitHandler, the payload includes the raw FormData and formDataJson from the submission.

export type FormSubmitHandler<TTransformedValues> = (payload: {
data: TTransformedValues
event?: React.BaseSyntheticEvent
formData: FormData
formDataJson: string
method?: "post" | "put" | "delete"
}) => unknown | Promise<unknown>

</> Control

import { useForm, useWatch, Control } from "react-hook-form"
type FormValues = {
firstName: string
lastName: string
}
function IsolateReRender({ control }: { control: Control<FormValues> }) {
const firstName = useWatch({
control,
name: "firstName",
defaultValue: "default",
})
return <div>{firstName}</div>
}
export default function App() {
const { register, control, handleSubmit } = useForm<FormValues>()
const onSubmit = handleSubmit((data) => console.log(data))
return (
<form onSubmit={onSubmit}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<IsolateReRender control={control} />
<input type="submit" />
</form>
)
}

</> UseFormReturn

export type UseFormReturn<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues = TFieldValues,
> = {
watch: UseFormWatch<TFieldValues>
getValues: UseFormGetValues<TFieldValues>
getFieldState: UseFormGetFieldState<TFieldValues>
setError: UseFormSetError<TFieldValues>
clearErrors: UseFormClearErrors<TFieldValues>
setValue: UseFormSetValue<TFieldValues>
setValues: UseFormSetValues<TFieldValues>
trigger: UseFormTrigger<TFieldValues>
formState: FormState<TFieldValues>
resetField: UseFormResetField<TFieldValues>
reset: UseFormReset<TFieldValues>
resetDefaultValues: UseFormResetDefaultValues<TFieldValues>
handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>
unregister: UseFormUnregister<TFieldValues>
control: Control<TFieldValues, TContext, TTransformedValues>
register: UseFormRegister<TFieldValues>
setFocus: UseFormSetFocus<TFieldValues>
subscribe: UseFormSubscribe<TFieldValues>
}
import type { FieldValues, UseFormReturn, SubmitHandler } from "react-hook-form"
import { useForm } from "react-hook-form"
type InputProps = React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => (
<input ref={ref} {...props} />
))
type Option = {
label: React.ReactNode
value: string | number | string[]
}
type SelectProps = React.DetailedHTMLProps<
React.SelectHTMLAttributes<HTMLSelectElement>,
HTMLSelectElement
> & { options: Option[] }
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ options, ...props }, ref) => (
<select ref={ref} {...props}>
{options.map(({ label, value }) => (
<option value={value}>{label}</option>
))}
</select>
)
)
type FormProps<TFormValues extends FieldValues> = {
onSubmit: SubmitHandler<TFormValues>
children: (methods: UseFormReturn<TFormValues>) => React.ReactNode
}
const Form = <TFormValues extends FieldValues>({
onSubmit,
children,
}: FormProps<TFormValues>) => {
const methods = useForm<TFormValues>()
return (
<form onSubmit={methods.handleSubmit(onSubmit)}>{children(methods)}</form>
)
}
type FormValues = {
firstName: string
lastName: string
sex: string
}
export default function App() {
const onSubmit = (data: FormValues) => console.log(data)
return (
<Form<FormValues> onSubmit={onSubmit}>
{({ register }) => (
<>
<Input {...register("firstName")} />
<Input {...register("lastName")} />
<Select
{...register("sex")}
options={[
{ label: "Female", value: "female" },
{ label: "Male", value: "male" },
{ label: "Other", value: "other" },
]}
/>
<Input type="submit" />
</>
)}
</Form>
)
}

</> UseFormProps

export type UseFormProps<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues = TFieldValues,
> = Partial<{
mode: Mode
disabled: boolean
reValidateMode: Exclude<Mode, "onTouched" | "all">
defaultValues: DefaultValues<TFieldValues> | AsyncDefaultValues<TFieldValues>
values: TFieldValues
errors: FieldErrors<TFieldValues>
resetOptions: Parameters<UseFormReset<TFieldValues>>[1]
resolver: Resolver<TFieldValues, TContext, TTransformedValues>
context: TContext
shouldFocusError: boolean
shouldUnregister: boolean
shouldUseNativeValidation: boolean
progressive: boolean
criteriaMode: CriteriaMode
delayError: number
formControl?: Omit<
UseFormReturn<TFieldValues, TContext, TTransformedValues>,
"formState"
>
validate: ValidateForm<TFieldValues>
}>

</> UseFormRegister

The type of register.

export type UseFormRegister<TFieldValues extends FieldValues> = <
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(
name: TFieldName,
options?: RegisterOptions<TFieldValues, TFieldName>
) => UseFormRegisterReturn<TFieldName>

</> UseFormRegisterReturn

The shape returned by invoking register. Useful for typing a custom Input component that spreads {...register(name)}.

export type UseFormRegisterReturn<
TFieldName extends InternalFieldName = InternalFieldName,
> = {
onChange: ChangeHandler
onBlur: ChangeHandler
ref: RefCallBack
name: TFieldName
min?: string | number
max?: string | number
maxLength?: number
minLength?: number
pattern?: string
required?: boolean
disabled?: boolean
}

</> UseFormUnregister

The type of unregister.

export type UseFormUnregister<TFieldValues extends FieldValues> = (
name?:
| FieldPath<TFieldValues>
| FieldPath<TFieldValues>[]
| readonly FieldPath<TFieldValues>[],
options?: Omit<
KeepStateOptions,
| "keepIsSubmitted"
| "keepSubmitCount"
| "keepValues"
| "keepDefaultValues"
| "keepErrors"
> & { keepValue?: boolean; keepDefaultValue?: boolean; keepError?: boolean }
) => void

</> UseFormWatch

The type of watch. Overloaded — called with no argument, a single field name, an array of field names, or a callback for subscribing without triggering a re-render.

export type UseFormWatch<TFieldValues extends FieldValues> = {
(): TFieldValues
<TFieldNames extends readonly FieldPath<TFieldValues>[]>(
names: readonly [...TFieldNames],
defaultValue?: DeepPartial<TFieldValues>
): FieldPathValues<TFieldValues, TFieldNames>
<TFieldName extends FieldPath<TFieldValues>>(
name: TFieldName,
defaultValue?: FieldPathValue<TFieldValues, TFieldName>
): FieldPathValue<TFieldValues, TFieldName>
(
callback: WatchObserver<TFieldValues>,
defaultValues?: DeepPartial<TFieldValues>
): Subscription
}

</> UseFormSubscribe

The type of subscribe — subscribe to formState changes without triggering a component re-render.

export type UseFormSubscribe<TFieldValues extends FieldValues> = <
TFieldNames extends readonly FieldPath<TFieldValues>[],
>(payload: {
name?: readonly [...TFieldNames] | TFieldNames[number]
formState?: Partial<ReadFormState>
callback: (
data: Partial<FormState<TFieldValues>> & {
values: TFieldValues
name?: InternalFieldName
type?: EventType
}
) => void
exact?: boolean
}) => () => void

</> UseFormHandleSubmit

The type of handleSubmit.

export type UseFormHandleSubmit<
TFieldValues extends FieldValues,
TTransformedValues = TFieldValues,
> = (
onValid: SubmitHandler<TTransformedValues>,
onInvalid?: SubmitErrorHandler<TFieldValues>
) => (e?: React.BaseSyntheticEvent) => Promise<void>

</> UseFormReset

The type of reset.

export type UseFormReset<TFieldValues extends FieldValues> = (
values?:
| DefaultValues<TFieldValues>
| TFieldValues
| ResetAction<TFieldValues>,
keepStateOptions?: KeepStateOptions
) => void

</> UseFormResetField

The type of resetField.

export type UseFormResetField<TFieldValues extends FieldValues> = <
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(
name: TFieldName,
options?: ResetFieldConfig<TFieldValues, TFieldName>
) => void

</> UseFormResetDefaultValues

The type of resetDefaultValues.

export type UseFormResetDefaultValues<TFieldValues extends FieldValues> = (
values: DefaultValues<TFieldValues> | TFieldValues,
options?: Partial<Pick<KeepStateOptions, "keepDirty" | "keepIsValid">>
) => void

</> UseFormSetError

The type of setError.

export type UseFormSetError<TFieldValues extends FieldValues> = (
name:
| FieldPath<TFieldValues>
| `root.${string}`
| "root"
| "form"
| `form.${string}`,
error: ErrorOption,
options?: {
shouldFocus: boolean
}
) => void

</> UseFormClearErrors

The type of clearErrors.

export type UseFormClearErrors<TFieldValues extends FieldValues> = (
name?:
| FieldPath<TFieldValues>
| FieldPath<TFieldValues>[]
| readonly FieldPath<TFieldValues>[]
| `root.${string}`
| "root"
| "form"
| `form.${string}`
) => void

</> UseFormSetValue

The type of setValue.

export type UseFormSetValue<TFieldValues extends FieldValues> = <
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(
name: TFieldName,
value: FieldPathValue<TFieldValues, TFieldName>,
options?: SetValueConfig
) => void

</> UseFormSetValues

The type of setValues.

export type UseFormSetValues<TFieldValues extends FieldValues> = (
value: Partial<TFieldValues> | ((formValues: TFieldValues) => TFieldValues),
options?: SetValueConfig
) => void

</> UseFormSetFocus

The type of setFocus.

export type SetFocusOptions = Partial<{
shouldSelect: boolean
}>
export type UseFormSetFocus<TFieldValues extends FieldValues> = <
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(
name: TFieldName,
options?: SetFocusOptions
) => void

</> UseFormGetValues

The type of getValues. Overloaded — called with no argument, a single field name, or an array of field names.

export type GetValuesConfig = {
dirtyFields?: boolean
touchedFields?: boolean
}
export type UseFormGetValues<TFieldValues extends FieldValues> = {
(name?: undefined, config?: GetValuesConfig): TFieldValues
<TFieldName extends FieldPath<TFieldValues>>(
name: TFieldName,
config?: GetValuesConfig
): FieldPathValue<TFieldValues, TFieldName>
<TFieldNames extends FieldPath<TFieldValues>[]>(
names: readonly [...TFieldNames],
config?: GetValuesConfig
): [...FieldPathValues<TFieldValues, TFieldNames>]
}

</> UseFormGetFieldState

The type of getFieldState.

export type UseFormGetFieldState<TFieldValues extends FieldValues> = <
TFieldName extends FieldPath<TFieldValues>,
>(
name: TFieldName,
formState?: FormState<TFieldValues>
) => {
invalid: boolean
isDirty: boolean
isTouched: boolean
isValidating: boolean
error?: FieldError
}

</> UseFormTrigger

The type of trigger.

export type TriggerConfig = Partial<{
shouldFocus: boolean
}>
export type UseFormTrigger<TFieldValues extends FieldValues> = (
name?:
| FieldPath<TFieldValues>
| FieldPath<TFieldValues>[]
| readonly FieldPath<TFieldValues>[],
options?: TriggerConfig
) => Promise<boolean>

</> UseWatchProps

The props accepted by useWatch.

export type UseWatchProps<TFieldValues extends FieldValues = FieldValues> = {
defaultValue?: unknown
disabled?: boolean
name?:
| FieldPath<TFieldValues>
| FieldPath<TFieldValues>[]
| readonly FieldPath<TFieldValues>[]
control?: Control<TFieldValues>
exact?: boolean
compute?: (formValues: TFieldValues) => TFieldValues
}

</> WatchProps

The props for the Watch render-prop component.

export type WatchProps<
TFieldName extends WatchName<TFieldValues>,
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues = TFieldValues,
TComputeValue = undefined,
> = {
control?: Control<TFieldValues, TContext, TTransformedValues>
name?: TFieldName
disabled?: boolean
exact?: boolean
defaultValue?: WatchDefaultValue<TFieldName, TFieldValues>
compute?: (value: WatchValue<TFieldName, TFieldValues>) => TComputeValue
render: (
value: WatchRenderValue<TFieldName, TFieldValues, TComputeValue>
) => React.ReactNode | React.ReactNode[]
}

</> UseFormStateProps

The props accepted by useFormState.

export type UseFormStateProps<
TFieldValues extends FieldValues,
TTransformedValues = TFieldValues,
> = Partial<{
control?: Control<TFieldValues, any, TTransformedValues>
disabled?: boolean
name?:
| FieldPath<TFieldValues>
| FieldPath<TFieldValues>[]
| readonly FieldPath<TFieldValues>[]
exact?: boolean
}>

</> FormStateSubscribeProps

The props for the FormStateSubscribe render-prop component.

export type FormStateSubscribeProps<
TFieldValues extends FieldValues,
TTransformedValues = TFieldValues,
> = UseFormStateProps<TFieldValues, TTransformedValues> & {
render: (values: UseFormStateReturn<TFieldValues>) => React.ReactNode
}

</> FormProviderProps

export type FormProviderProps<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues = TFieldValues,
> = {
children: React.ReactNode | React.ReactNode[]
} & UseFormReturn<TFieldValues, TContext, TTransformedValues>

</> FormProps

export type FormProps<
TFieldValues extends FieldValues,
TTransformedValues = TFieldValues,
> = Omit<React.FormHTMLAttributes<HTMLFormElement>, "onError" | "onSubmit"> &
Partial<{
control: Control<TFieldValues, any, TTransformedValues>
headers: Record<string, string>
validateStatus: (status: number) => boolean
onError: (
payload:
| { response: Response; error?: undefined }
| { response?: undefined; error: unknown }
) => void
onSuccess: ({ response }: { response: Response }) => void
onSubmit: FormSubmitHandler<TTransformedValues>
method: "post" | "put" | "delete"
children: React.ReactNode | React.ReactNode[]
render: (props: {
submit: (e?: React.FormEvent) => void
}) => React.ReactNode | React.ReactNode[]
encType:
| "application/x-www-form-urlencoded"
| "multipart/form-data"
| "text/plain"
| "application/json"
}>

</> UseFieldArrayReturn

export type UseFieldArrayReturn<
TFieldValues extends FieldValues = FieldValues,
TFieldArrayName extends
FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
TKeyName extends string = "id",
> = {
swap: UseFieldArraySwap
move: UseFieldArrayMove
prepend: UseFieldArrayPrepend<TFieldValues, TFieldArrayName>
append: UseFieldArrayAppend<TFieldValues, TFieldArrayName>
remove: UseFieldArrayRemove
insert: UseFieldArrayInsert<TFieldValues, TFieldArrayName>
update: UseFieldArrayUpdate<TFieldValues, TFieldArrayName>
replace: UseFieldArrayReplace<TFieldValues, TFieldArrayName>
fields: (FieldArrayWithId<TFieldValues, TFieldArrayName, TKeyName> & {
disabled?: boolean
})[]
}

</> FieldArrayMethodProps

Focus options accepted as the second argument to append, prepend, and insert.

export type FieldArrayMethodProps = {
shouldFocus?: boolean
focusIndex?: number
focusName?: string
}

</> UseFieldArrayProps

export type UseFieldArrayProps<
TFieldValues extends FieldValues = FieldValues,
TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
TKeyName extends string = 'id',
TTransformedValues = TFieldValues,
> = {
name: TFieldArrayName
keyName?: TKeyName
control?: Control<TFieldValues, any, TTransformedValues>
rules?: {
validate?
| Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>
| Record<
string,
Validate<FieldArray<TFieldValues, TFieldArrayName>[], TFieldValues>
>
} & Pick<
RegisterOptions<TFieldValues>,
'maxLength' | 'minLength' | 'required'
>
shouldUnregister?: boolean
disabled?: boolean
}

</> FieldArrayProps

export type FieldArrayProps<
TFieldValues extends FieldValues = FieldValues,
TFieldArrayName extends
FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
TKeyName extends string = "id",
> = {
render: (
fieldArray: UseFieldArrayReturn<TFieldValues, TFieldArrayName, TKeyName>
) => React.ReactElement
} & UseFieldArrayProps<TFieldValues, TFieldArrayName, TKeyName>

</> ControllerRenderProps

The shape of the field object passed to Controller's render prop. Useful for typing a custom controlled input component.

export type ControllerRenderProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
onChange: (...event: any[]) => void
onBlur: Noop
value: FieldPathValue<TFieldValues, TName>
disabled?: boolean
name: TName
ref: RefCallBack
}

</> ControllerFieldState

The shape of the fieldState object passed to Controller's render prop.

export type ControllerFieldState = {
invalid: boolean
isTouched: boolean
isDirty: boolean
isValidating: boolean
error?: FieldError
}

</> UseControllerReturn

export type UseControllerReturn<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
field: ControllerRenderProps<TFieldValues, TName>
formState: UseFormStateReturn<TFieldValues>
fieldState: ControllerFieldState
}

</> UseControllerProps

export type UseControllerProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TTransformedValues = TFieldValues,
> = {
name: TName
rules?: Omit<
RegisterOptions<TFieldValues, TName>,
"valueAsNumber" | "valueAsDate" | "setValueAs" | "disabled"
>
shouldUnregister?: boolean
defaultValue?: FieldPathValue<TFieldValues, TName>
control?: Control<TFieldValues, any, TTransformedValues>
disabled?: boolean
exact?: boolean
}

</> ControllerProps

export type ControllerProps<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TTransformedValues = TFieldValues,
> = {
render: ({
field,
fieldState,
formState,
}: {
field: ControllerRenderProps<TFieldValues, TName>
fieldState: ControllerFieldState
formState: UseFormStateReturn<TFieldValues>
}) => React.ReactElement
} & UseControllerProps<TFieldValues, TName, TTransformedValues>

</> FieldError

export type FieldError = {
type: LiteralUnion<keyof RegisterOptions, string>
root?: FieldError
ref?: Ref
types?: MultipleFieldErrors
message?: Message
}

</> FieldErrors

export type FieldErrors<T extends FieldValues = FieldValues> = Partial<
FieldValues extends IsAny<FieldValues>
? any
: FieldErrorsImpl<DeepRequired<T>>
> & {
root?: Record<string, GlobalError> & GlobalError
form?: GlobalError
}

</> ErrorOption

The error object accepted by setError.

export type ErrorOption = {
message?: Message
type?: LiteralUnion<keyof RegisterOptions, string>
types?: MultipleFieldErrors
}

</> Field

export type Field = {
_f: {
ref: Ref
name: InternalFieldName
refs?: HTMLInputElement[]
mount?: boolean
} & RegisterOptions
}

</> FieldPath

This type is useful when you define custom component's name prop, and it will type check against your field path.

export type FieldPath<TFieldValues extends FieldValues> = Path<TFieldValues>

</> FieldPathByValue

This type will return union with all available paths that match the passed value

export type FieldPathByValue<TFieldValues extends FieldValues, TValue> = {
[Key in FieldPath<TFieldValues>]: FieldPathValue<
TFieldValues,
Key
> extends TValue
? Key
: never
}[FieldPath<TFieldValues>]

</> FieldValues

export type FieldValues = Record<string, any>

</> FieldArrayWithId

export type FieldArrayWithId<
TFieldValues extends FieldValues = FieldValues,
TFieldArrayName extends
FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
TKeyName extends string = "id",
> = FieldArray<TFieldValues, TFieldArrayName> & Record<TKeyName, string>

</> Mode

export type ValidationMode = typeof VALIDATION_MODE
export type Mode = keyof ValidationMode

</> RegisterOptions

export type RegisterOptions<
TFieldValues extends FieldValues = FieldValues,
TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = Partial<{
required: Message | ValidationRule<boolean>
min: ValidationRule<number | string>
max: ValidationRule<number | string>
maxLength: ValidationRule<number>
minLength: ValidationRule<number>
validate:
| Validate<FieldPathValue<TFieldValues, TFieldName>, TFieldValues>
| Record<
string,
Validate<FieldPathValue<TFieldValues, TFieldName>, TFieldValues>
>
value: FieldPathValue<TFieldValues, TFieldName>
setValueAs: (value: any) => any
shouldUnregister?: boolean
onChange?: (event: any) => void
onBlur?: (event: any) => void
disabled: boolean
deps: FieldPath<TFieldValues> | FieldPath<TFieldValues>[]
}> &
(
| {
pattern?: ValidationRule<RegExp>
valueAsNumber?: false
valueAsDate?: false
}
| {
pattern?: undefined
valueAsNumber?: false
valueAsDate?: true
}
| {
pattern?: undefined
valueAsNumber?: true
valueAsDate?: false
}
)

</> FormState

The type of formState, returned by useForm and useFormState.

export type FormState<TFieldValues extends FieldValues> = {
isDirty: boolean
isLoading: boolean
isSubmitted: boolean
isSubmitSuccessful: boolean
isSubmitting: boolean
isValidating: boolean
isValid: boolean
disabled: boolean
submitCount: number
defaultValues?: undefined | Readonly<DeepPartial<TFieldValues>>
dirtyFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>
touchedFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>
validatingFields: Partial<Readonly<FieldNamesMarkedBoolean<TFieldValues>>>
errors: FieldErrors<TFieldValues>
isReady: boolean
}

</> KeepStateOptions

Options accepted by reset and useForm's resetOptions, controlling which parts of form state survive the reset.

export type KeepStateOptions = Partial<{
keepDirtyValues: boolean
keepErrors: boolean
keepDirty: boolean
keepValues: boolean
keepDefaultValues: boolean
keepIsSubmitted: boolean
keepIsSubmitSuccessful: boolean
keepTouched: boolean
keepIsValidating: boolean
keepIsValid: boolean
keepSubmitCount: boolean
keepFieldsRef: boolean
}>

</> FormStateProxy

export type FormStateProxy<TFieldValues extends FieldValues = FieldValues> = {
isDirty: boolean
isValidating: boolean
dirtyFields: FieldNamesMarkedBoolean<TFieldValues>
touchedFields: FieldNamesMarkedBoolean<TFieldValues>
validatingFields: FieldNamesMarkedBoolean<TFieldValues>
errors: boolean
isValid: boolean
}

</> NestedValue (Deprecated at 7.33.0)

import { useForm, NestedValue } from "react-hook-form"
import { TextField, Select } from "@material-ui/core"
import { Autocomplete } from "@material-ui/lab"
type Option = {
label: string
value: string
}
const options = [
{ label: "Chocolate", value: "chocolate" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Vanilla", value: "vanilla" },
]
export default function App() {
const {
register,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<{
autocomplete: NestedValue<Option[]>
select: NestedValue<number[]>
}>({
defaultValues: { autocomplete: [], select: [] },
})
const onSubmit = handleSubmit((data) => console.log(data))
React.useEffect(() => {
register("autocomplete", {
validate: (value) => value.length || "This is required.",
})
register("select", {
validate: (value) => value.length || "This is required.",
})
}, [register])
return (
<form onSubmit={onSubmit}>
<Autocomplete
options={options}
getOptionLabel={(option: Option) => option.label}
onChange={(e, options) => setValue("autocomplete", options)}
renderInput={(params) => (
<TextField
{...params}
error={Boolean(errors?.autocomplete)}
helperText={errors?.autocomplete?.message}
/>
)}
/>
<Select
value=""
onChange={(e) => setValue("select", e.target.value as number[])}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
</Select>
<input type="submit" />
</form>
)
}
import { useForm, NestedValue } from "react-hook-form"
type FormValues = {
key1: string
key2: number
key3: NestedValue<{
key1: string
key2: number
}>
key4: NestedValue<string[]>
}
const {
formState: { errors },
} = useForm<FormValues>()
errors?.key1?.message // no type error
errors?.key2?.message // no type error
errors?.key3?.message // no type error
errors?.key4?.message // no type error

Thank you for your support

If you find React Hook Form to be useful in your project, please consider to star and support it.

Edit