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

如何将Base子类作为WeakMap的键(忽略构造签名差异)

解决TypeScript中WeakMap键约束为Base子类的类型问题

问题根源

你定义的WeakMap<new(args:object)=>Base, number>要求键的构造函数必须接受任意object类型的参数,但子类A、B、C的构造签名和这个约束不兼容:

  • A需要{a:string}类型的参数(比object更具体)
  • C需要两个参数,和单参数的约束完全不匹配

函数参数遵循逆变原则:如果目标类型要求宽泛的参数,源类型的具体参数无法赋值给它,这就是类型报错的核心原因。

解决方案

定义一个能兼容所有Base子类构造函数的类型,只要求构造函数能产出Base实例,不限制参数类型:

class Base {
  constructor(args: {}) {}
}

class A extends Base {
  constructor(args: { a: string }) {
    super(args);
  }
}

class B extends Base {
  constructor(args: { b: number }) {
    super(args);
  }
}

class C extends Base {
  constructor(args: {}, other: number) {
    super(args);
  }
}

// 定义兼容所有Base子类的构造函数类型
type BaseConstructor = new (...args: any[]) => Base;

const myMap: WeakMap<BaseConstructor, number> = new WeakMap([
  [Base, 0],
  [A, 1],
  [B, 2],
  [C, 3]
]);

// 调用get方法也不会报错
console.log(myMap.get(A)); // 1

为什么这个方案可行?

  • BaseConstructor类型允许构造函数接受任意数量、任意类型的参数,只要最终返回Base或其子类实例
  • 所有继承自Base的子类构造函数都能匹配这个类型,既满足了类型约束,又没有忽略类型检查(仍然会拒绝非Base子类的构造函数)

替代方案(避免any)

如果你不想使用any,可以用unknown替代,核心逻辑一致:

type BaseConstructor = new (...args: unknown[]) => Base;

不过在这个场景下,any的使用是合理的——我们只关心构造函数的输出(Base实例),不需要约束输入参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:27:01