如何为React自定义useForm Hook实现TypeScript泛型类型推导
TypeScript 类型适配实现方案
要实现useForm自动根据传入初始值推导返回inputs的精确类型,只需要给Hook添加泛型约束即可,不需要在调用时手动重复声明类型。
完整带类型的Hook实现
import { useState, ChangeEvent } from 'react'; // 定义泛型T,约束为普通对象类型,TS会自动从入参推导T的具体结构 const useForm = <T extends Record<string, any>>(initial: T) => { const [inputs, setInputs] = useState<T>(initial); // 表单输入变更方法,覆盖常用表单元素类型 const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => { const { name, value, type } = e.target; // 针对数字输入做类型转换,避免数字字段被转为字符串 const finalValue = type === 'number' ? Number(value) : value; setInputs(prev => ({ ...prev, [name]: finalValue })); }; // 重置表单为初始值 const resetForm = () => setInputs(initial); // 清空表单内容 const clearInputs = () => { const emptyState = Object.fromEntries( Object.entries(initial).map(([key, val]) => [key, typeof val === 'number' ? 0 : '']) ) as T; setInputs(emptyState); }; return { inputs, onChange, resetForm, clearInputs }; };
实现说明
- 泛型参数
T会在调用Hook时,由TS自动根据传入的initial参数推导精确结构,不需要调用方手动传入泛型 - 给
useState指定泛型T后,返回的inputs会完全继承初始值的字段类型,不会出现any类型的问题 onChange方法内置了数字类型转换逻辑,只要给对应输入框设置type="number",就能保证数字字段的类型一致性
调用效果验证
原有业务代码不需要任何修改,就能获得精准的类型提示:
// inputs自动推导为 { name: string; age: number; city: string } const { inputs, onChange: handleChange, resetForm } = useForm({ name: "", age: 25, city: "Amsterdam" });
其他场景调用也会自动适配类型:
// inputs自动推导为 { distance: number; hours: number; speed: number } const { inputs } = useForm({ distance: 40, hours: 2, speed: 5 });
如果你使用了自定义表单输入组件,可以根据实际组件的事件参数类型,调整
onChange方法的入参类型即可。
内容的提问来源于stack exchange,提问作者Justin van Dijk
相关产品推荐
相关产品推荐

