reactjs - Använd generisk som skickas till useForm i anpassad kontrollkomponent


Genom att använda react-hook-form försöker jag göra en egen ControlledTextField-komponent som fungerar med mitt komponentbibliotek. Följande TypeScript-användning för userForm kan jag skapa mitt formulär på detta sätt

export interface AuthenticationData {
  email: string,
  password: string
}
const { handleSubmit, control } = useForm<AuthenticationData>({
  resolver: yupResolver(LoginSchema),
})

Sedan skapar jag min anpassade ControlledTextField-komponent

import { FormControl, Input } from "native-base"
import { Controller, UseControllerProps } from "react-hook-form"

interface ControlledTextFieldProps extends UseControllerProps {
  label: string
}

const ControlledTextField = ({ control, name, label, ...props }: ControlledTextFieldProps) => {
  return (
    <Controller
      control={control}
      name={name}
      render={({
        fieldState: { invalid, error },
        field: { onChange, onBlur, value },
      }) => (
        <FormControl mb="5" isInvalid={invalid}>
          <FormControl.Label>{label}</FormControl.Label>
          <Input
            onBlur={onBlur}
            onChange={onChange}
            value={value}
          />
          <FormControl.ErrorMessage>
            {error?.message ?? ""}
          </FormControl.ErrorMessage>
        </FormControl>
      )}
    />
  )
}

export default ControlledTextField

När jag försöker implementera får jag detta fel

Type 'Control<AuthenticationData, any>' is not assignable to type 'Control<FieldValues, any>'.
  The types of '_options.resolver' are incompatible between these types.
    Type 'Resolver<AuthenticationData, any> | undefined' is not assignable to type 'Resolver<FieldValues, any> | undefined'.
      Type 'Resolver<AuthenticationData, any>' is not assignable to type 'Resolver<FieldValues, any>

Implementeringen ser ut så här...

<ControlledTextField
  name="email"
  label="Email"
  control={control}
/>

Svar #1

Jag har också stött på det här problemet. Lösningen jag kom fram till var att skicka Control-prop:n med en generisk typ som utökar FieldValues-typen till ControlledTextField-komponenten. Från och med då bör du kunna få olika variabler med de korrekt härledda typerna.

Komponentimplementeringen bör se ut ungefär så här:

import { FormControl, Input } from "native-base"
import { Controller, UseControllerProps, Control, FieldPath, FieldValues } from "react-hook-form"

interface ControlledTextFieldProps<T extends FieldValues> extends UseControllerProps {
  label: string;
  control: Control<T>;
  name: FieldPath<T>;
  defaultValue: T[keyof T];
}

const ControlledTextField = ({ control, name, label, defaultValue, ...props }: ControlledTextFieldProps) => {
  return (
    <Controller
      control={control}
      name={name}
      render={({
        fieldState: { invalid, error },
        field: { onChange, onBlur, value },
      }) => (
        <FormControl mb="5" isInvalid={invalid}>
          <FormControl.Label>{label}</FormControl.Label>
          <Input
            onBlur={onBlur}
            onChange={onChange}
            value={value}
          />
          <FormControl.ErrorMessage>
            {error?.message ?? ""}
          </FormControl.ErrorMessage>
        </FormControl>
      )}
    />
  )
}

export default ControlledTextField

Och sedan, när du implementerar komponenten:

<ControlledTextField
  name="email"
  label="Email"
  control={control}
  defaultValue=""
/>