reactjs - Hvordan gi fleksibel typetilordning for en tilpasset Input-komponent ved bruk av React Hook Form med TypeScript


Hvis jeg har en generell Input-komponent i en React Hook Form som kan brukes både for registrerings- og innloggingsskjemaer, hvordan kan jeg gjøre IFormValues fleksibel, slik at den kan brukes for begge skjemaene som har forskjellige inputfelt? Registrering har inputfelt for e-post, passord og bekreft passord, mens Innlogging kun har inputfelt for e-post og passord.

interface IFormValues {
  email: string;
  password: string;
  confirmPassword: string;
}

type InputProps = {
  hookValue: Path<IFormValues>;
  register: UseFormRegister<IFormValues>;
  id: string;
  ...etc
};

const Input = ({ hookValue, id, ...etc }: InputProps) => 
  <StyledInput {...register(hookValue)} id={id} ...etc />

Ville det være en unionstype som dette? (eller er det en måte å sende inn den riktige typen som brukes til input-komponenten?)

interface ISignIn {
  email: string;
  password: string;
}

interface ISignUp extends ISignIn {
  confirmPassword: string;
}

type InputProps = {
  hookValue: Path<ISignIn | ISignUp>;
  register: UseFormRegister<ISignIn | ISignUp>;
  id: string;
  ...etc
};

Jeg prøvde å implementere med det ovenfor, men dette gir meg følgende TypeScript-feil når jeg kaller komponenten:

<Input
  register={register} // this errors with the below output
  hookValue="email"
  label="Email"
/>
(property) register: UseFormRegister<ISignUp | ISignIn>
Type 'UseFormRegister<{ email: string; password: string; confirmPassword: string; }>' is not assignable to type 'UseFormRegister<ISignUp | ISignIn>'.
  Type 'ISignUp | ISignIn' is not assignable to type '{ email: string; password: string; confirmPassword: string; }'.
    Property 'confirmPassword' is missing in type 'ISignIn' but required in type '{ email: string; password: string; confirmPassword: string; }'.ts(2322)
input.component.tsx(24, 3): The expected type comes from property 'register' which is declared here on type 'IntrinsicAttributes & InputProps'

Svar #1

Jeg klarte å få dette til å fungere med følgende, ved å bruke extend som jeg forstår fungerer som en begrensning på generisk type - i praksis sikrer det at den kan tilordnes den typen, men beholder den strengere utledede verdien.

export type ISignIn = {
  email: string;
  password: string;
};

export type ISignUp = {
  email: string;
  password: string;
  confirmPassword: string;
};

type InputProps<IFormValues extends ISignIn | ISignUp> = {
  hookValue: Path<IFormValues>;
  register: UseFormRegister<IFormValues>;
};

const Input = <IFormValues extends ISignIn | ISignUp>({
  hookValue,
  register,
}: InputProps<IFormValues>) => {

Svar #2

løsning 1: bruk &-operatoren som ISignIn & ISignUp

løsning 2: typeof-type-vakter

Relaterte artikler