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

TypeScript中正确声明继承抽象基类的扩展类类型的方法

问题场景

定义抽象基类BaseClass以及多个继承并实现其抽象方法的扩展子类,需要在函数中实例化扩展类后存入普通JS对象,初始实现代码如下:

abstract class BaseClass {
    abstract fun(): void;
}

class ExtendedClassA extends BaseClass {
    fun(): void {
        console.log("Class A");
    }
}

class ExtendedClassB extends BaseClass {
    fun(): void {
        console.log("Class B");
    }
}

type ExtendedObjects = { [name: string]: BaseClass };
type ExtendedClasses =  { [name: string]: BaseClass };

const extendedObjects: ExtendedObjects= {}
const extendedClasses: ExtendedClasses = { A: ExtendedClassA, B: ExtendedClassB }

function initializeBaseObject(key: string): void {
   extendedObjects[key] = new extendedClasses[key];
}

initializeBaseObject("A");
initializeBaseObject("B")

extendedObjects["A"].fun();
extendedObjects["B"].fun();

编写上述代码时TypeScript抛出报错:

This expression is not constructible. Type 'BaseClass ' has no construct signatures.

该报错符合预期:BaseClass是抽象类,本身不具备构造签名,无法直接通过new调用。
此前尝试通过any与BaseClass做交叉类型的方式消除报错:

type ExtendedObjects = { [name: string]: any & BaseClass };
type ExtendedClasses =  { [name: string]: any & BaseClass };

但该方案引入了不安全的any类型,不符合类型安全要求。

实际业务约束:

  • 所有扩展类定义在独立模块中,无法预先知晓extendedClasses对象中包含的具体类
  • 仅能确定所有存入的类均继承自BaseClass
  • 需要不使用any的类型安全声明方案
类型安全解决方案

报错的核心原因是类型定义错配:

  • ExtendedObjects用于存储实例化后的对象,值类型为BaseClass子类实例,原类型定义正确
  • ExtendedClasses用于存储类本身(即构造函数),原类型定义错误地将值类型写为BaseClass实例,而非可构造的类类型

只需要给ExtendedClasses定义带构造签名的类型即可,完全不需要使用any:

// 存储实例:值为BaseClass子类实例
type ExtendedObjects = { [name: string]: BaseClass };
// 存储类本身:值为无参构造函数,调用后返回BaseClass子类实例
type ExtendedClasses = { [name: string]: new () => BaseClass };

如果扩展类的构造函数需要传入参数,可以根据实际参数类型调整构造签名,例如支持任意参数的写法为new (...args: unknown[]) => BaseClass。

修正后可直接通过TS类型校验,完整代码如下:

abstract class BaseClass {
    abstract fun(): void;
}

class ExtendedClassA extends BaseClass {
    fun(): void {
        console.log("Class A");
    }
}

class ExtendedClassB extends BaseClass {
    fun(): void {
        console.log("Class B");
    }
}

type ExtendedObjects = { [name: string]: BaseClass };
type ExtendedClasses =  { [name: string]: new () => BaseClass };

const extendedObjects: ExtendedObjects= {}
const extendedClasses: ExtendedClasses = { A: ExtendedClassA, B: ExtendedClassB }

function initializeBaseObject(key: string): void {
   extendedObjects[key] = new extendedClasses[key];
}

initializeBaseObject("A");
initializeBaseObject("B")

extendedObjects["A"].fun();
extendedObjects["B"].fun();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:18:33