如何在TypeScript中收窄数组中的联合类型?
TypeScript联合类型数组的类型收窄问题解决方法
你遇到的核心问题是:typeof event === "EventB"这个判断完全无效,因为typeof只能检测JavaScript原始类型(如string、number、boolean等),而TypeScript的自定义接口类型在编译后会被擦除,运行时根本不存在EventB这个类型标识,所以TypeScript无法通过这个判断收窄类型。
以下是几种正确的处理方式:
1. 属性存在性检查
利用两个接口的独有属性进行判断,TypeScript会自动识别这种检查并收窄类型:
events.forEach(event => { if ('attrB' in event) { // 此处event已被收窄为EventB,可直接访问attrB const bAttr = event.attrB; } else { // 此处event已被收窄为EventA,可直接访问attrA const aAttr = event.attrA; } })
2. 自定义类型守卫函数
如果类型判断逻辑更复杂,可以写一个类型守卫函数明确告诉TypeScript如何区分类型:
// 类型守卫函数,返回值为类型谓词 function isEventB(event: BaseEvent): event is EventB { return (event as EventB).attrB !== undefined; } events.forEach(event => { if (isEventB(event)) { console.log(event.attrB); } else { console.log((event as EventA).attrA); } })
3. 添加可区分联合的类型标识(推荐)
给每个接口添加一个字面量类型的标识字段,TypeScript会自动将其识别为可区分联合,类型收窄会非常直观:
interface BaseEvent { id: number; type: string; } interface EventA extends BaseEvent { type: 'EventA'; // 字面量类型,明确标识类型 attrA: string; } interface EventB extends BaseEvent { type: 'EventB'; attrB: string; } type Events = (EventA | EventB)[]; const events: Events = [ { id: 1, type: 'EventA', attrA: "A" }, { id: 2, type: 'EventB', attrB: "B" } ] events.forEach(event => { if (event.type === 'EventB') { // 自动收窄为EventB console.log(event.attrB); } else { // 自动收窄为EventA console.log(event.attrA); } })
你之前尝试的交集类型不适合这个场景,交集类型的作用是让类型同时拥有多个类型的属性,而你需要的是区分联合类型中的不同成员,两者解决的是完全不同的问题。
内容的提问来源于stack exchange,提问作者Enfield Li
相关产品推荐
相关产品推荐

