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

TypeScript中使用泛型扩展抽象类的类型问题

问题描述

在扩展接受泛型T的抽象类TestClass时,希望ImplTestClass类中eventList属性的类型为AllowedEvents所有可能值组成的联合类型数组,但当前实现无法达到预期,求解决方法。

type EventMap = Record<string, unknown>; 

abstract class TestClass<T extends EventMap> {
  public eventList: Array<T[keyof T]>;

  constructor() {
    this.eventList = [];
  }
}


interface AllowedEvents extends EventMap {
  created: { time: string; userId: number; createdId: number; },
  removed: { time: string; userId: number; removedId: number; }
}

class ImplTestClass extends TestClass<AllowedEvents> {
  getEventList() {
    return this.eventList;
    // 期望eventList的类型为
    // ({ time: string; userId: number; createdId: number; } | { time: string; userId: number; removedId: number; })
  }
};
解决方案

问题根源在于EventMap的定义:Record<string, unknown>会让T[keyof T]被推断为unknown,因为unknown是所有类型的父类型,TypeScript无法保留具体的联合类型信息。以下是几种可行的修改方案:

方案1:调整EventMap的类型约束

将EventMap改为更具体的结构类型,避免用unknown抹平类型差异:

// 替换原有的EventMap定义
type EventMap = { [key: string]: object }; 

abstract class TestClass<T extends EventMap> {
  public eventList: Array<T[keyof T]>;

  constructor() {
    this.eventList = [];
  }
}

方案2:直接在抽象类泛型中定义约束

如果不需要单独的EventMap类型,可以直接在抽象类的泛型约束里指定结构:

abstract class TestClass<T extends { [key: string]: object }> {
  public eventList: Array<T[keyof T]>;

  constructor() {
    this.eventList = [];
  }
}

方案3:用工具类型显式提取值类型

先定义一个提取对象值类型的工具类型,让代码逻辑更清晰:

type ValueOf<T> = T[keyof T];

abstract class TestClass<T extends { [key: string]: object }> {
  public eventList: ValueOf<T>[];

  constructor() {
    this.eventList = [];
  }
}

以上任意方案修改后,ImplTestClass中的eventList都会被正确推断为你期望的联合类型数组:
({ time: string; userId: number; createdId: number; } | { time: string; userId: number; removedId: number; })[]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:03:16