react-hook-form复用Select组件遇TS2322类型不兼容错误求助
解决react-hook-form与MUI Select组件的TypeScript类型不兼容问题
问题描述
我基于MUI 5.11和react-hook-form实现了一个可复用Select组件,组件代码如下:
...someImports import { Control, Controller } from 'react-hook-form'; interface SelectProps { control: Control; ...someProps } export interface SelectOption { title: string; value: any; } const Select: FC<SelectProps> = ({ ...props }) => { return ( <Controller control={control} name={name} render={({ field }) => ( <FormControl {...props} fullWidth> <InputLabel id={label}>{label}</InputLabel> <MuiSelect ..someOptions > {options.map((option) => ( <MenuItem value={option.value}>{option.title}</MenuItem> ))} </MuiSelect> </FormControl> )} /> ); }; export default Select;
在使用该组件时触发TypeScript错误:
TS2322: Type 'Control<FormFields, any>' is not assignable to type 'Control<FieldValues, any>'.
使用场景代码:
interface FormFields { name: string; age: number; } const { control, handleSubmit, setValue, watch } = useForm<FormFields>() <Grid container columnGap={5} alignItems="stretch" sx={{ width: '500px' }}> <Grid xs={4}> <Select control={control} // 此处control出现类型报错
解决方案
问题根源在于Select组件的Control类型未做泛型约束,默认使用Control<FieldValues>,与使用时传入的Control<FormFields>类型不匹配。通过给组件添加泛型支持即可解决:
- 修改SelectProps接口,添加泛型约束
import { Control, Controller, FieldValues } from 'react-hook-form'; // 新增泛型T,约束表单字段类型 interface SelectProps<T extends FieldValues> { control: Control<T>; name: keyof T; // 约束name必须是表单字段的键,提升类型安全性 label: string; options: SelectOption[]; // 其他自定义props } export interface SelectOption { title: string; value: any; }
- 让Select组件支持泛型
// 组件定义时接收泛型T const Select = <T extends FieldValues>({ control, name, label, options, ...props }: SelectProps<T>) => { return ( <Controller control={control} name={name} render={({ field }) => ( <FormControl {...props} fullWidth> <InputLabel id={`${label}-id`}>{label}</InputLabel> <MuiSelect labelId={`${label}-id`} {...field} label={label} > {options.map((option) => ( <MenuItem key={option.value} value={option.value}> {option.title} </MenuItem> ))} </MuiSelect> </FormControl> )} /> ); }; export default Select;
- 使用组件(自动推断或显式指定泛型)
TypeScript会自动从useForm<FormFields>的control推断出泛型类型,也可以显式指定:
<Select<FormFields> control={control} name="age" // 此时name会被约束为FormFields的键(name/age),避免拼写错误 label="年龄" options={[ { title: "18", value: 18 }, { title: "20", value: 20 } ]} />
修改后,组件的control类型会与使用时的表单字段类型保持一致,TypeScript报错即可消除。
内容的提问来源于stack exchange,提问作者PttRulez
相关产品推荐
相关产品推荐

