如何使用可选判别器收窄TypeScript可辨识联合类型?
问题背景
我正在实现一个类React Select的组件,通过可选的isMulti布尔值支持单选/多选(未提供时默认false),采用可辨识联合类型定义Props,但在调用onChange时TypeScript无法正确推断参数类型,报错如下:
Argument of type 'OptionValue | OptionValue[]' is not assignable to parameter of type 'OptionValue & OptionValue[]'.
Type 'OptionValue' is not assignable to type 'OptionValue & OptionValue[]'.
Type 'OptionValue' is missing the following properties from type 'OptionValue[]': length, pop, push, concat, and 26 more.
核心原因
单独提取props.value后,它与isMulti的类型关联被切断,TypeScript无法将value和onChange的类型匹配起来——此时onChange是两种函数类型的联合,要求参数必须同时满足两种类型的交集,导致报错。
解决方案
方案1:通过isMulti直接收窄整个Props类型
保持isMulti、value、onChange的类型关联,通过检查props.isMulti来收窄Props的具体类型,TypeScript会自动推断对应value和onChange的类型:
type OptionValue = { label: string; value: string; } interface CommonProps { className?: string; disabled?: boolean; options: OptionValue[]; } interface SingleValueProps extends CommonProps { isMulti?: false; value: OptionValue | null; onChange: (value: OptionValue) => void; } interface MultiValueProps extends CommonProps { isMulti: true; value: OptionValue[]; onChange: (value: OptionValue[]) => void; } export type Props = SingleValueProps | MultiValueProps; function Component(props: Props) { function handleChange() { if (props.isMulti) { // 此处Props被收窄为MultiValueProps类型 props.onChange(props.value); } else { // 此处Props被收窄为SingleValueProps类型 const selectedValue = props.value; if (selectedValue != null) { props.onChange(selectedValue); } } } // 组件渲染逻辑 } // 测试用例 Component({ isMulti: true, value: [], onChange: (value) => console.log("多选值:", value), options: [] }) Component({ isMulti: false, value: {label: "选项1", value: "opt1"}, onChange: (value) => console.log("单选值:", value), options: [] }) Component({ value: {label: "选项1", value: "opt1"}, onChange: (value) => console.log("单选值(默认):", value), options: [] })
方案2:自定义类型守卫(按需使用)
如果需要单独处理value,可以编写自定义类型守卫来明确Props的类型:
// 自定义类型守卫 function isMultiProps(props: Props): props is MultiValueProps { return props.isMulti === true; } function Component(props: Props) { const selectedValue = props.value; function handleChange() { if (isMultiProps(props)) { props.onChange(selectedValue); // 自动推断为OptionValue[] } else { if (selectedValue != null) { props.onChange(selectedValue); // 自动推断为OptionValue } } } }
关键要点
必须保持可辨识联合中各个属性的类型关联,不能单独提取某一属性后脱离辨识符(isMulti)的约束,否则TypeScript无法完成类型匹配。
内容的提问来源于stack exchange,提问作者Andrew Nicolaou

