TypeScript联合类型数组:如何识别类型并拦截非法属性组合
解决TypeScript联合类型允许非法交叉对象的问题
要让同时包含IMenuItem和IMenuDivider属性的对象触发类型错误,核心是把原来的“包容型联合类型”改成互斥型联合类型,有两种常用方案:
方案1:添加鉴别属性(推荐)
给每个接口添加一个唯一的type属性作为鉴别标识,让TypeScript能明确区分不同类型的成员,自然排除交叉情况:
// 修改后的接口 interface IMenuItem { type: 'item'; // 唯一鉴别值 label: string; onClick: () => void; } interface IMenuDivider { type: 'divider'; // 唯一鉴别值 } // 互斥的联合类型 type TItem = IMenuItem | IMenuDivider;
此时如果传入同时包含两类属性的对象:
// 会触发类型错误:不存在同时满足type: 'divider'和label/onClick的类型 const invalidItem: TItem = { type: 'divider', label: 'Test', onClick: () => {} };
方案2:用never排除交叉属性
如果不想新增鉴别属性,可以通过交叉never类型,强制每个类型不能包含另一类型的核心属性:
// 原接口保持不变 interface IMenuItem { label: string; onClick: () => void; } interface IMenuDivider { type: 'divider'; } // 定义互斥联合类型:每个分支排除另一类型的属性 type TItem = | (IMenuItem & { type?: never }) // 不允许有type属性 | (IMenuDivider & { label?: never; onClick?: never }); // 不允许有label/onClick属性
此时传入交叉对象会直接报错,因为没有分支能匹配同时拥有两类属性的结构。
原理说明
TypeScript默认的联合类型是“包容式”的——只要对象满足联合类型中至少一个成员的结构,就会被判定为合法。通过上述两种方式,我们把联合类型改成了“互斥式”:对象必须严格匹配其中一个成员的结构,不能同时满足多个。
内容的提问来源于stack exchange,提问作者Uri Klar
相关产品推荐
相关产品推荐

