如何用keyof为React通用表单变更处理器正确添加类型?
如何为通用React表单变更处理器添加正确的TypeScript类型
我有多个React表单,想要实现一个通用的表单变更处理器来更新状态对象的不同字段,需要为该处理器添加合适的类型约束,让错误的字段值调用触发编译错误。现有代码示例如下:
interface Data { a: string; b: number; } let data: Data = {a: "a", b: 1}; function changeHandler<T>(field: keyof Data, value: T) { data = {...data, [field]: value} } // 应该通过编译 changeHandler("a", "aa"); changeHandler("b", 11); // 应该触发编译错误 changeHandler("a", 1); changeHandler("b", "b"); console.log(data);
注:示例已简化,实际应用中使用React.useState替代let变量。
解决方案:通过泛型关联字段名与值类型
原代码中的泛型T是独立的,TypeScript无法建立field和value之间的类型关联,导致错误调用无法被检测。我们需要用泛型参数绑定字段名和对应值类型,实现强类型约束:
正确的类型实现
interface Data { a: string; b: number; } let data: Data = {a: "a", b: 1}; // 泛型K约束为Data的字段名,value类型固定为该字段对应的类型 function changeHandler<K extends keyof Data>(field: K, value: Data[K]) { data = {...data, [field]: value}; } // 正常通过编译 changeHandler("a", "aa"); changeHandler("b", 11); // 触发编译错误(类型不匹配) changeHandler("a", 1); // 类型“number”不能赋值给类型“string” changeHandler("b", "b"); // 类型“string”不能赋值给类型“number” console.log(data);
原理说明
- 泛型
K被限制为keyof Data,只能传入Data的合法字段名 value的类型直接指定为Data[K],即当前字段K在Data中定义的类型- 这样TypeScript会在编译时自动校验:传入的
value必须和field对应的字段类型完全匹配,错误调用会直接触发编译报错
React项目中的实际应用(结合useState)
在React场景下,结合useState的写法如下:
import { useState } from 'react'; interface Data { a: string; b: number; } function MyForm() { const [data, setData] = useState<Data>({a: "a", b: 1}); const changeHandler = <K extends keyof Data>(field: K, value: Data[K]) => { setData(prevState => ({...prevState, [field]: value})); }; return ( <div> <input type="text" value={data.a} onChange={(e) => changeHandler("a", e.target.value)} /> <input type="number" value={data.b} onChange={(e) => changeHandler("b", Number(e.target.value))} /> </div> ); }
内容的提问来源于stack exchange,提问作者jansepke
相关产品推荐
相关产品推荐

