TypeScript中抽象类如何强制派生类使用不同构造签名并隐藏内部属性?
问题描述
我有一个抽象基类BaseDefiningModelType<T>,它的构造函数接收T的构造函数并赋值给只读的modelType,供派生类内部创建T实例使用:
export abstract class BaseDefiningModelType<T> { public readonly modelType: new () => T; constructor(type: new () => T) { this.modelType = type; } }
基于这个基类可以派生出构造函数签名不同的抽象子类:
export abstract class SpecializedBase<T> extends BaseDefiningModelType<T> { constructor(options: {[key: string]: any}); }
以下是具体的实现类示例:
export class BaseImpl extends BaseDefiningModelType<Foo> { private opt1: string; constructor(options: { opt1?: string }) { super(Foo); this.opt1 = options.opt1 || 'default'; } } export class SpecializedImpl extends SpecializedBase<Bar> { private opt1: string; constructor(options: { opt1?: number }) { super(options); this.opt1 = options.opt1 || 'default'; } }
我需要统一引用这些实现类的类型,目前的写法是:
const myTypes: (new (options: {[key: string]: any}) => BaseDefiningModelType<any>)[] = [ BaseImpl, SpecializedImpl, ]
但现在有两个需求:
BaseDefiningModelType的构造函数仅允许派生类内部调用,外部代码不能直接使用modelType属性对实现类的消费者完全隐藏,不能被外部访问
请问该如何实现?
解决方案
1. 限制基类构造函数与内部属性的访问权限
把BaseDefiningModelType的构造函数改为protected,同时将modelType的访问级别也设为protected。这样只有派生类能调用基类构造函数、访问modelType,外部代码会直接因权限问题报错:
export abstract class BaseDefiningModelType<T> { // 改为protected,仅派生类可访问 protected readonly modelType: new () => T; // 构造函数改为protected,禁止外部直接实例化或调用 protected constructor(type: new () => T) { this.modelType = type; } }
补充SpecializedBase的构造函数实现(需要根据实际逻辑从options中获取T的构造函数,示例假设options包含type字段):
export abstract class SpecializedBase<T> extends BaseDefiningModelType<T> { constructor(options: {[key: string]: any}) { // 这里替换为你的实际逻辑,解析options得到T的构造函数 super(options.type as new () => T); } }
2. 定义对外暴露的公共接口
创建一个不包含任何内部细节的公共接口,所有实现类对外只暴露这个接口的能力,消费者仅依赖该接口:
// 定义消费者需要的公共能力,比如创建实例的方法 export interface ModelInstance { createModel(): any; }
让基类实现这个接口,把modelType的使用封装在接口方法内部,对外隐藏具体实现:
export abstract class BaseDefiningModelType<T> implements ModelInstance { protected readonly modelType: new () => T; protected constructor(type: new () => T) { this.modelType = type; } // 对外提供创建实例的方法,内部使用modelType createModel(): T { return new this.modelType(); } }
3. 统一构造函数类型
定义一个专门的构造函数类型,指向返回ModelInstance的构造函数,这样myTypes就用这个类型,完全屏蔽基类的内部结构:
// 统一的构造函数类型,接收任意options并返回ModelInstance type ModelConstructor = new (options: {[key: string]: any}) => ModelInstance; const myTypes: ModelConstructor[] = [ BaseImpl, SpecializedImpl, ];
效果验证
现在外部代码无法进行以下操作:
// 错误:BaseDefiningModelType的构造函数是protected,无法直接实例化 new BaseDefiningModelType(Foo); // 错误:modelType是protected,外部无法访问 const instance = new BaseImpl({}); instance.modelType;
消费者只能通过ModelInstance接口定义的方法与实例交互,完全看不到基类的内部细节。
内容的提问来源于stack exchange,提问作者Harps
相关产品推荐
相关产品推荐

