You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:35:33