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

为何TypeScript无法从子类类型推断基类泛型类型?

问题分析与解决

问题现象

在TypeScript 4.9.3中,以下代码里ExtractEvents<FooEmitter>的推断结果是EventsMap而非预期的FooEvents,导致ShouldBeTrue2返回false:

// @strict: true
type EventsMap = Record<string, (...args: any[]) => any>;

declare class TypedEmitter<L extends EventsMap>
{
  on<U extends keyof L>(event: U, listener: L[U]): this;
  off<U extends keyof L>(event: U, listener: L[U]): this;
  emit<U extends keyof L>(event: U, ...args: Parameters<L[U]>): boolean;
}

type ExtractEvents<Candidate> = Candidate extends TypedEmitter<infer E>
  ? E
  : never;

type FooEvents = {
  foo: (payload: string) => void;
}

declare class FooEmitter extends TypedEmitter<FooEvents> {}

type ExtendsFooEvents<C> = C extends FooEvents ? true : false;

// 结果为true,符合预期
type ShouldBeTrue1 = ExtendsFooEvents<ExtractEvents<TypedEmitter<FooEvents>>>;

// 结果为false,不符合预期
type ShouldBeTrue2 = ExtendsFooEvents<ExtractEvents<FooEmitter>>;

原因解释

这是TypeScript泛型继承中的类型推断行为导致的:

  • 当直接传入TypedEmitter<FooEvents>时,TypeScript能明确识别这是泛型类的具体实例化,因此infer E会直接推断为FooEvents。
  • 但当传入子类FooEmitter时,TypeScript仅能识别它继承自TypedEmitter<L extends EventsMap>,此时条件类型会优先使用泛型参数的约束上限(即EventsMap)作为推断结果,而非父类实例化时传入的具体类型FooEvents。子类的实例类型不会自动保留父类的具体泛型参数信息。

解决方案

有两种简洁的修复方式:

方案1:在父类中添加类型推断用的幽灵属性

在TypedEmitter中添加一个仅用于类型推断的属性(无需实际实现),用来显式绑定泛型参数L:

declare class TypedEmitter<L extends EventsMap>
{
  // 幽灵属性,仅用于类型系统推断
  declare readonly __eventMap: L;
  on<U extends keyof L>(event: U, listener: L[U]): this;
  off<U extends keyof L>(event: U, listener: L[U]): this;
  emit<U extends keyof L>(event: U, ...args: Parameters<L[U]>): boolean;
}

// 修改ExtractEvents来读取这个属性
type ExtractEvents<Candidate> = Candidate extends { __eventMap: infer E } 
  ? E 
  : never;

方案2:调整条件类型的推断逻辑

通过嵌套条件类型,强制TypeScript深入推断具体的泛型参数:

type ExtractEvents<Candidate> = 
  Candidate extends TypedEmitter<infer E> 
    ? E extends EventsMap ? E : never
    : never;

两种方案都能让ExtractEvents<FooEmitter>正确推断为FooEvents,使得ShouldBeTrue2返回true。

内容的提问来源于stack exchange,提问作者Jules Sam. Randolph

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:25:18