TypeScript如何通过抽象类实现服务单例以消除代码重复?
TypeScript 服务类单例的代码复用方案
你需要为多个服务类实现单例模式,目前每个类都重复编写了getInstance方法和静态实例的代码。尝试用抽象泛型类复用逻辑时,遇到两个核心问题:
- 静态成员无法引用类的泛型参数(报错
Static members cannot reference class type parameters) - 无法通过泛型类型
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
相关产品推荐
相关产品推荐

