React Native中使用React Hook Form的TypeScript类型错误求助
问题解决:React Hook Form + TypeScript 受控组件name属性类型错误
问题背景
在React Native项目里用React Hook Form实现表单控制时,给ControlledTextInput传name属性(比如"username")时出现TypeScript类型错误,提示"username"不能赋值给never类型。
代码示例
Home表单组件
import { useForm } from 'react-hook-form'; import ControlledTextInput from './ControlledTextInput'; import { View } from 'react-native'; type FormValues = { username: string; password: string; }; export default function Home() { const { control } = useForm<FormValues>({ defaultValues: { username: '', password: '', }, }); return ( <View> <ControlledTextInput control={control} name="username" // ❌ 此处出现类型错误 placeholder="用户名" /> <ControlledTextInput control={control} name="password" // ❌ 此处出现类型错误 placeholder="密码" secureTextEntry /> </View> ); }
ControlledTextInput受控输入组件
import { Controller, Control } from 'react-hook-form'; import Input from './Input'; type ControlledTextInputProps = { control: Control; name: string; placeholder: string; secureTextEntry?: boolean; }; export default function ControlledTextInput({ control, name, placeholder, secureTextEntry, }: ControlledTextInputProps) { return ( <Controller control={control} name={name} render={({ field: { onChange, value } }) => ( <Input onChangeText={onChange} value={value} placeholder={placeholder} secureTextEntry={secureTextEntry} /> )} /> ); }
Input基础输入组件
import { TextInput, TextInputProps } from 'react-native'; type InputProps = TextInputProps & { // 自定义属性(如有) }; export default function Input(props: InputProps) { return <TextInput {...props} />; }
错误原因
ControlledTextInput的类型定义太笼统:control用了无泛型的Control类型,name只是普通string,完全没和表单的FormValues类型关联。React Hook Form无法推断出name应该是FormValues里的合法键,直接把name的类型判定为never,导致传入合法字段名也报错。
修复方案
给ControlledTextInput添加泛型,让它和表单的FormValues类型挂钩,TypeScript就能准确识别合法的name字段了。
修改后的ControlledTextInput代码:
import { Controller, Control, FieldPath } from 'react-hook-form'; import Input from './Input'; // 新增泛型T,关联表单值类型 type ControlledTextInputProps<T> = { control: Control<T>; // 用FieldPath<T>约束name必须是T的合法键 name: FieldPath<T>; placeholder: string; secureTextEntry?: boolean; }; // 组件改为泛型组件 export default function ControlledTextInput<T>({ control, name, placeholder, secureTextEntry, }: ControlledTextInputProps<T>) { return ( <Controller control={control} name={name} render={({ field: { onChange, value } }) => ( <Input onChangeText={onChange} value={value} placeholder={placeholder} secureTextEntry={secureTextEntry} /> )} /> ); }
在Home组件中使用时,显式指定泛型(TypeScript也可自动推断,显式声明更清晰):
<ControlledTextInput<FormValues> control={control} name="username" // ✅ 类型检查通过 placeholder="用户名" /> <ControlledTextInput<FormValues> control={control} name="password" // ✅ 类型检查通过 placeholder="密码" secureTextEntry />
额外说明
FieldPath<T>是React Hook Form提供的工具类型,专门用来约束表单字段名,能避免拼写错误或传入不存在的字段。- 改成泛型组件后,
ControlledTextInput可以复用在任何结构的表单中,只需传入对应的表单值类型即可。
内容的提问来源于stack exchange,提问作者Ming
相关产品推荐
相关产品推荐

