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

为何TypeScript中stack[k]的类型推断为交集而非并集?

TypeScript泛型函数中索引类型推断为交叉类型的原因

下面的TypeScript代码定义了事件回调相关类型及泛型函数test,但在给stack[k]赋值时出现了不符合预期的类型推断:

export type EventCallbackStackType = {
    StringEvent?: Array<(data: string) => void>;
    ArrayEvent?: Array<(data: string[]) => void>;
};

export type EventCallbackKeysType = keyof EventCallbackStackType;

export type EventCallbackType<T extends EventCallbackKeysType> = Exclude<EventCallbackStackType[T], undefined>[number];

export type CallbackType = EventCallbackType<EventCallbackKeysType>

const test = <T extends EventCallbackKeysType>(k: T, v: EventCallbackType<T>) => {
    const stack: EventCallbackStackType = {}
    stack[k] = [v] // 此处出现类型错误
}

此时stack[k]的类型被推断为:

((data: string) => void)[] & ((data: string[]) => void)[]   

而非预期的联合类型:

((data: string) => void)[] | ((data: string[]) => void)[]

原因分析

核心问题出在TypeScript处理泛型索引访问的逻辑上:

  • 当使用泛型类型T extends EventCallbackKeysType作为索引时,TypeScript无法在编译阶段确定T到底是"StringEvent"还是"ArrayEvent",只会把它看作联合类型"StringEvent" | "ArrayEvent"的子类型。
  • 在赋值场景下,TypeScript会采用"安全兜底"的推断逻辑:为了保证无论T是哪个具体键,赋值操作都能兼容所有可能的情况,它会将stack[k]的类型推断为所有对应属性类型的交叉类型——交叉类型要求值同时满足所有类型的约束,这显然在这个场景下是不可能实现的,因为两种回调数组类型完全不兼容。
  • 简单来说,TypeScript误以为k可能同时指向两个属性(虽然运行时不可能),所以强制要求赋值的数组必须同时是两种回调类型的数组,最终得到了那个矛盾的交叉类型,导致报错。

内容的提问来源于stack exchange,提问作者Twist Lee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:53:29