Mohammad-Faisal/react-hook-form-material-ui

Creating reusable text field component using Material UI and react-hook-form

Opened this issue · 0 comments

I was trying to develop reusable text field component using Material UI and reach-hook-form. I was referring following examples (first one is from react-hook-form docs, second one is this repo):

Can we use this example from react-hook-form docs to introduce generic type in your FormInputProps

    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>
      );
    };

Related code in this repo:

   //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}
         />
       )}
     />
   );
 };

But, 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<...>'

Why am I getting this error?