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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:01:03