设置React Hook Form defaultValues后注册输入遇TS2345错误求助
我是React和React Hook Form新手,正在开发实时更新的简历生成器。设置表单defaultValues后,注册输入时遇到TypeScript错误(TS:2345)。
默认值定义:
export const defaultData = { name: 'John Doe', email: 'john@mail.com', number: '416-123-4567', address: 'California' }
App组件中配置useForm:
function App(): JSX.Element { const { register, setValue, watch } = useForm({ defaultValues: defaultData });
循环注册输入时触发错误:
Argument of type 'string' is not assignable to parameter of type "number" | "name" | "email" | "address" (TS:2345)
相关代码:
inputs={section.inputs.map((iField) => { const field = iField.field; //field是输入属性名 return ( <div key={iField.id} className="inputField"> <label>{iField.title}</label> <input {...register(field)} onChange={(e: React.ChangeEvent<HTMLInputElement>) => { setValue(field, e.target.value); }} ></input> </div> ); })}
defaultData的属性均为string类型,请问为何会出现该错误?
原因分析
TypeScript 无法推断出iField.field的类型是defaultData的属性名(即"name" | "email" | "number" | "address"),而是将其识别为宽泛的string类型。而React Hook Form的register和setValue方法要求传入的字段名必须是表单数据对象的已知属性,类型不匹配因此触发报错。
解决方法
方法1:为字段列表定义精确类型
基于defaultData生成表单字段的精确类型,让TypeScript明确字段名的合法范围:
// 从defaultData提取所有属性名的类型 type FormFieldName = keyof typeof defaultData; // 定义单个输入字段的类型,限制field为合法属性名 interface InputField { id: string; title: string; field: FormFieldName; } // 确保section的inputs是InputField数组类型 interface Section { inputs: InputField[]; }
之后TypeScript就能确认iField.field是合法的表单字段名,错误会自动消失。
方法2:类型断言(不推荐)
如果无法提前定义类型,可以临时用类型断言强制告诉TS字段名的合法性:
{...register(field as FormFieldName)} // 以及 setValue(field as FormFieldName, e.target.value);
注意:这种方式会跳过TypeScript的类型检查,一旦字段名写错会导致运行时错误,因此仅在特殊场景下使用,优先推荐方法1。
额外优化
你代码中手动添加的onChange调用setValue是多余的——register方法已经自动处理了输入值与表单状态的同步,删除这段onChange逻辑不影响功能,还能简化代码。
内容的提问来源于stack exchange,提问作者user25352645

