If I have a generic Input component in a React Hook Form that can be used for both sign up & sign in forms, how can I make the IFormValues flexible, so that it can be used for both forms that have different inputs?
Sign Up has email, password and confirmPassword inputs, whereas Sign In only has email and password inputs.
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 />
Would it be a union type like this? (or is there a way to pass in the correct type being used to the input component?)
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
};
I tried implementing with the above, but this is producing the below TypeScript error for me in the call to the component:
<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'
2
Answers
I managed to get this working with the following, using extend which as I understand acts as a constraint on the generic - essentially making sure it's assignable to that type but keeping its stricter inferred value.
solution 1: use & operator like ISignIn & ISignUp
solution 2: typeof-type-guards