React Hook Form复用表单字段组件时TypeScript类型不兼容问题求助
React Hook Form复用表单字段组件时TypeScript类型不兼容问题求助
嘿,我完全懂你遇到的坑——本来想着RegisterFormFields继承了LoginFormFields,复用组件应该顺理成章,结果TypeScript反而给你抛了类型错误对吧?这其实是因为**UseFormRegister的类型是逆变的**:简单说就是,如果RegisterFormFields是LoginFormFields的子类型,UseFormRegister<RegisterFormFields>并不能赋值给UseFormRegister<LoginFormFields>,逻辑刚好反过来,所以编译器就卡壳了。
解决这个问题的核心是让你的字段组件支持泛型,这样它们就能适配任意扩展LoginFormFields的类型,不管是登录还是注册表单都能通用。我给你具体改一下代码:
第一步:改造EmailField组件(PasswordField同理)
把原来固定死LoginFormFields的类型改成泛型,让组件接受一个扩展LoginFormFields的类型参数:
import { FieldErrors, UseFormRegister } from 'react-hook-form'; import { LoginFormFields } from '../../login/loginForm'; // 改成泛型接口,T必须扩展LoginFormFields interface EmailFieldParameterTypes<T extends LoginFormFields> { register: UseFormRegister<T>; errors: FieldErrors<T>; } // 组件也改成泛型组件 const EmailField = <T extends LoginFormFields>({ register, errors }: EmailFieldParameterTypes<T>) => { return ( <label className="flex flex-col gap-1"> <div>Email</div> <input className="p-2 border border-gray-500 shadow bg-gray-200" id="email-input" type="email" placeholder={"enter your email"} {...register("email", { required: "email is required!" })} /> {errors.email && <p className="text-red-400">{errors.email.message}</p>} </label> ); }; export default EmailField;
第二步:PasswordField做同样的改造
和EmailField逻辑一致,把PasswordField的接口和组件都改成泛型,确保它也能适配LoginFormFields或其子类型:
// passwordField.tsx示例 import { FieldErrors, UseFormRegister } from 'react-hook-form'; import { LoginFormFields } from '../../login/loginForm'; interface PasswordFieldParameterTypes<T extends LoginFormFields> { register: UseFormRegister<T>; errors: FieldErrors<T>; } const PasswordField = <T extends LoginFormFields>({ register, errors }: PasswordFieldParameterTypes<T>) => { return ( <label className="flex flex-col gap-1"> <div>Password</div> <input className="p-2 border border-gray-500 shadow bg-gray-200" id="password-input" type="password" placeholder={"enter your password"} {...register("password", { required: "password is required!" })} /> {errors.password && <p className="text-red-400">{errors.password.message}</p>} </label> ); }; export default PasswordField;
第三步:验证使用场景
现在不管是LoginForm还是RegisterForm使用这些组件,TypeScript都会自动推断出对应的泛型参数,不会再报错了:
- LoginForm里的
useForm<LoginFormFields>返回的register和errors,会让EmailField自动匹配T=LoginFormFields - RegisterForm里的
useForm<RegisterFormFields>返回的register和errors,会让EmailField自动匹配T=RegisterFormFields
这样既实现了字段组件的复用,又完美保持了TypeScript的类型安全~
备注:内容来源于stack exchange,提问作者icardiolog
相关产品推荐
相关产品推荐

