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

TypeScript如何通过抽象类实现服务单例以消除代码重复?

TypeScript 服务类单例的代码复用方案

你需要为多个服务类实现单例模式,目前每个类都重复编写了getInstance方法和静态实例的代码。尝试用抽象泛型类复用逻辑时,遇到两个核心问题:

  1. 静态成员无法引用类的泛型参数(报错Static members cannot reference class type parameters)
  2. 无法通过泛型类型T直接实例化对象

错误原因

  • 静态成员属于类构造函数本身,而泛型参数是类实例层面的类型参数,静态上下文无法访问泛型T
  • TypeScript的类型信息在编译阶段会被擦除,new T()在运行时没有对应的构造函数引用,无法创建实例

方案1:通用单例工厂函数

创建一个工厂函数,接收服务类的构造函数,返回带有单例逻辑的方法。每个服务类只需挂载这个方法即可,彻底消除重复代码:

function createSingleton<T>(ctor: new () => T): { getInstance(): T } {
  let instance: T;
  return {
    getInstance(): T {
      if (!instance) {
        instance = new ctor();
      }
      return instance;
    }
  };
}

// 服务类实现
class Service1 {
  private constructor() {} // 私有构造,禁止外部直接new
  static getInstance = createSingleton(Service1).getInstance;
}

class Service2 {
  private constructor() {}
  static getInstance = createSingleton(Service2).getInstance;
}

// 调用示例
const s1 = Service1.getInstance();
const s1Again = Service1.getInstance();
console.log(s1 === s1Again); // true

方案2:装饰器实现单例

利用TypeScript装饰器给类注入单例逻辑,代码更简洁,调用时直接new即可:

function Singleton<T extends new (...args: any[]) => any>(ctor: T) {
  let instance: InstanceType<T>;
  return class extends ctor {
    constructor(...args: any[]) {
      if (instance) return instance;
      super(...args);
      instance = this;
    }
  };
}

// 服务类实现
@Singleton
class Service1 {
  private constructor() {}
}

@Singleton
class Service2 {
  private constructor() {}
}

// 调用示例
const s2 = new Service2();
const s2Again = new Service2();
console.log(s2 === s2Again); // true

注意:使用装饰器需要在tsconfig.json中开启experimentalDecorators和emitDecoratorMetadata配置项。

方案3:继承基类的兼容写法

如果坚持用类继承的方式,可以让子类注册自身的构造函数,绕过泛型静态成员的限制:

abstract class BaseService {
  protected static instance: BaseService;
  protected static ctor: new () => BaseService;

  protected constructor() {}

  public static getInstance(): BaseService {
    if (!this.instance) {
      this.instance = new this.ctor();
    }
    return this.instance;
  }
}

// 服务类实现
class Service1 extends BaseService {
  private static override ctor = Service1;
  private constructor() { super(); }

  // 重写getInstance返回正确的类型
  public static override getInstance(): Service1 {
    return super.getInstance() as Service1;
  }
}

class Service2 extends BaseService {
  private static override ctor = Service2;
  private constructor() { super(); }

  public static override getInstance(): Service2 {
    return super.getInstance() as Service2;
  }
}

// 调用示例
const s3 = Service1.getInstance();

内容的提问来源于stack exchange,提问作者Oğuz Öztınaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:02:26