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

TypeScript中带protected构造函数的泛型getInstance调用报错解决方案

解决TypeScript中带protected构造函数的泛型单例实现问题

问题根源

原代码的错误在于getInstance方法的this参数类型new () => T要求构造函数是**公共(public)**的,但子类的构造函数是受保护(protected)的,TypeScript不允许将受保护构造函数类型赋值给公共构造函数类型。此外,原代码所有子类共享父类的instance属性,导致多个子类无法拥有各自的单例实例。

解决方案

我们可以通过以下调整实现需求:

  1. 使用Map存储每个子类的单例实例,确保每个子类拥有独立的单例
  2. 修改this参数类型为父类的类型typeof Singleton,兼容受保护构造函数的子类
  3. 在父类静态方法中利用类层级访问权限创建子类实例

修正后的代码

class Singleton {
  // 用Map存储每个子类的单例实例,键为类构造函数,值为实例
  private static instances = new Map<typeof Singleton, Singleton>();
   
  protected constructor() {}

  public static getInstance<T extends Singleton>(this: typeof Singleton): T {
    if (!Singleton.instances.has(this)) {
      // 利用父类对protected构造函数的访问权限创建实例
      Singleton.instances.set(this, new this());
    }
    // 返回对应子类的实例,类型断言为T是安全的
    return Singleton.instances.get(this) as T;
  }
}

class Child extends Singleton {
  someMethod(): void {
    console.log("Child method called");
  }
}

// 现在调用不再报错
const childInstance = Child.getInstance();
childInstance.someMethod(); // 输出: Child method called

// 测试子类的单例特性
console.log(childInstance === Child.getInstance()); // true

// 新增子类验证独立单例
class GrandChild extends Child {
  anotherMethod(): void {
    console.log("GrandChild method called");
  }
}

const grandChildInstance = GrandChild.getInstance();
grandChildInstance.anotherMethod(); // 输出: GrandChild method called
console.log(grandChildInstance === GrandChild.getInstance()); // true
console.log(childInstance !== grandChildInstance); // true

关键说明

  • Map存储实例:避免了所有子类共享父类实例的问题,每个子类通过自身构造函数作为键获取独立实例
  • this参数类型调整:typeof Singleton兼容所有子类的类型(即使构造函数是protected),解决了原有的类型不匹配错误
  • protected构造函数访问:父类的静态方法属于类层级,有权访问子类的protected构造函数,因此new this()是合法的

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:45:02