React-select组件onChange回调值类型不匹配报错排查
react-hook-form 集成 react-select 时 onChange 类型报错修复
现有代码
初始选择器组件实现:
import { Controller } from "react-hook-form"; import Select, { StylesConfig } from "react-select"; //.. const [universe, setUniverse] = useState<SetStateAction<TOption | unknown>>(null); <Controller name="universe_id" control={control} // 来自react-hook-form的control实例 rules={{ required: true }} render={({ field }) => ( <Select {...field} value={universe} onChange={handleUniverseChange} options={universeOptions} styles={selectStyles as StylesConfig} /> )} />
项目自定义TOption类型定义:
export type TOption = { label: string | number; value: string | number; };
报错表现
两种类型声明方式都会触发TS错误:
- 将onChange入参声明为
unknown类型时,函数内访问item.value触发类型报错:const handleUniverseChange = (item: unknown ) => { setUniverse(item); setValue("universe_id", item.value); // 对象类型为unknown }; - 将onChange入参声明为
TOption类型时,Select组件onChange属性绑定处抛出类型不匹配错误:
具体错误信息:const handleUniverseChange = (item: TOption) => { // 业务逻辑 }错误:类型"(item: TOption) => void"不能赋值给类型"(newValue: unknown, actionMeta: ActionMeta) => void"
问题原因
- react-select的
Select是泛型组件,未显式传入泛型参数时,onChange的第一个入参默认推导为unknown类型,无法直接匹配自定义的TOption - 现有state类型定义存在问题:一是useState泛型参数写法错误,
SetStateAction是React内置的setState函数参数类型,不需要手动包裹在useState泛型中;二是TOption | unknown的联合类型等价于unknown,完全丢失了TOption的类型约束,同时没有覆盖选择器清空值时返回null的场景 - 未对选中值做空值收窄,直接访问属性不符合TS类型安全要求
修复方案
- 修正useState类型,移除错误的
SetStateAction包裹和无意义的unknown联合类型,补充null类型适配清空选择的场景 - 给
Select组件显式传入泛型参数,指定选项类型为TOption,TS会自动推导onChange入参类型 - 在onChange逻辑中增加空值判断,做类型收窄后再访问value属性
修复后完整代码:
import { Controller } from "react-hook-form"; import Select, { StylesConfig } from "react-select"; // 引入自定义TOption类型 // import type { TOption } from "@/types"; // 修正state类型 const [universe, setUniverse] = useState<TOption | null>(null); <Controller name="universe_id" control={control} rules={{ required: true }} render={({ field }) => ( {/* 显式传入泛型指定选项类型 */} <Select<TOption> {...field} value={universe} onChange={(item) => { setUniverse(item); // 空值判断做类型收窄 if (item) { setValue("universe_id", item.value); } else { // 清空选择时重置表单字段值 setValue("universe_id", undefined); } }} options={universeOptions} styles={selectStyles as StylesConfig} /> )} />
补充说明:如果使用多选模式,泛型需要写为Select<TOption, true>,此时onChange入参类型会自动推导为readonly TOption[]。
内容的提问来源于stack exchange,提问作者Randall
相关产品推荐
相关产品推荐

