如何将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
相关产品推荐
相关产品推荐

