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

TypeScript如何通过映射类型窄化常量映射表的实例类类型

问题原因
  • 方法入参key的类型被写死为WidgetType全量联合类型,没有和泛型参数T绑定,TS无法建立入参和返回值的关联
  • TS默认不会对常量对象的动态索引访问做跨泛型的类型窄化,动态取构造函数实例化时,会默认推导为所有可能实例的联合类型
修复实现

只需要做两处调整即可实现精准类型推导:

  1. 将getHandler的入参类型从WidgetType改为T,让入参和泛型强绑定
  2. 对映射表取出的构造函数做对应泛型的类型断言(逻辑上保证枚举值和映射表一一对应,类型安全)

修复后完整可运行代码:

export enum WidgetType {
  PIE = "pie",
  BAR = "bar",
  COUNTER = "counter",
}
class CounterHandler{}
class GroupValuesHandler{}

const HANDLERS_MAP = {
  [WidgetType.COUNTER]: CounterHandler,
  [WidgetType.BAR]: GroupValuesHandler,
  [WidgetType.PIE]: GroupValuesHandler,
} as const;

export type GetHandler<T extends WidgetType> = {
  [K in WidgetType]: typeof HANDLERS_MAP[K];
}[T];

// 验证单独类型推导正常
type B = GetHandler<WidgetType.COUNTER>; // CounterHandler

export class WidgetHandlerMapper {
  public getHandler<T extends WidgetType>(
    key: T,
  ): InstanceType<GetHandler<T>> {
    const HandlerClass = HANDLERS_MAP[key] as GetHandler<T>;
    return new HandlerClass();
  }
}

const mapper = new WidgetHandlerMapper()
const counterHandler = mapper.getHandler(WidgetType.COUNTER); // 类型为CounterHandler,符合预期
const barHandler = mapper.getHandler(WidgetType.BAR); // 类型为GroupValuesHandler,符合预期
const pieHandler = mapper.getHandler(WidgetType.PIE); // 类型为GroupValuesHandler,符合预期
补充说明
  • 该实现要求HANDLERS_MAP必须覆盖WidgetType的所有枚举值,如果存在遗漏会出现运行时错误,可按需增加运行时判空兜底逻辑
  • 如果需要更强的类型校验,也可以通过方法重载逐个声明每个枚举值对应的返回类型,但是泛型方案代码更简洁,后续新增枚举值时不需要同步修改方法签名,维护成本更低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:06:35