I was trying to develop reusable text field component using Material UI and reach-hook-form. I was referring following examples:
-
Example 1 ref:
type FormProps<TFormValues> = { onSubmit: SubmitHandler<TFormValues>; children: (methods: UseFormReturn<TFormValues>) => React.ReactNode; }; const Form = <TFormValues extends Record<string, any> = Record<string, any>>({ onSubmit, children }: FormProps<TFormValues>) => { const methods = useForm<TFormValues>(); return ( <form onSubmit={methods.handleSubmit(onSubmit)}>{children(methods)}</form> ); };
-
Example 2 ref:
//https://github.com/Mohammad-Faisal/react-hook-form-material-ui/blob/master/src/form-components/FormInputProps.ts export interface FormInputProps { name: string; control: any; label: string; setValue?: any; } //https://github.com/Mohammad-Faisal/react-hook-form-material-ui/blob/master/src/form-components/FormInputText.tsx import React from "react"; import { Controller, useFormContext } from "react-hook-form"; import TextField from "@material-ui/core/TextField"; import { FormInputProps } from "./FormInputProps"; export const FormInputText = ({ name, control, label }: FormInputProps) => { return ( <Controller name={name} control={control} render={({ field: { onChange, value }, fieldState: { error }, formState, }) => ( <TextField helperText={error ? error.message : null} size="small" error={!!error} onChange={onChange} value={value} fullWidth label={label} variant="outlined" /> )} /> ); };
After analyzing both, I came up with following:
import { TextField } from "@mui/material";
import { Controller, UseFormReturn } from "react-hook-form";
interface IRhfTextBoxProps<TFormValues> {
name: string;
methods: UseFormReturn<TFormValues>;
}
// export const RhfTextBox = <TFormValues extends unknown>(props : IRhfTextBoxProps<TFormValues>) => { //##1
export const RhfTextBox = <TFormValues extends Record<string, any> = Record<string, any>>( // ##2 similar to example 1
props: IRhfTextBoxProps<TFormValues>
) => {
return (
<Controller
control={props.methods.control}
name={props.name} // ##3
render={({ field, fieldState, formState }) => (
<TextField
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
key={props.name}
/>
)}
/>
);
};
Both lines ##1
and ##2
in above code gives following error at line ##3
:
Type 'string' is not assignable to type 'Path<TFormValues>'.
The detailed error message is as follows:
The expected type comes from property 'name' which is declared here on type 'IntrinsicAttributes & { render: ({ field, fieldState, formState, }: { field: ControllerRenderProps<TFormValues, Path<TFormValues>>; fieldState: ControllerFieldState; formState: UseFormStateReturn<...>; }) => ReactElement<...>; } & UseControllerProps<...>'
Q1. Why am I getting this error?
Q2. Should I just use non generics FormInputProps
as in example 2, instead of generics based FormProps
in example 1.