网站搜索

抽象类实现的 TypeScript 类型声明


我正在尝试找出如何提供一个类型定义,对应于“所有实现某个抽象类的类”。看看下面的代码示例:

abstract class AbstractFoo {
  abstract foo()
}

class Concrete1 extends AbstractFoo {
  foo() { ... }
}

class Concrete1 extends AbstractFoo {
  foo() { ... }
}

现在,我正在尝试创建一个从 string 到某个具体类的映射。请注意,我 不是 尝试映射到具体类的实例。请参见以下内容:

const myMap: Map<string, typeINeedHelpWith> = new Map()
myMap.set('concrete1string', Concrete1)
myMap.set('concrete2string', Concrete2)

const instantiatedConcrete1 = new myMap.get('concrete1string')(...)

是否有一个 typeINeedHelpWith 的类型定义可以让我实现这个?

答案#1

使用一个返回具体实例作为映射值的函数。

更新:以下建议仅适用于 deno

作为建议,最好使用 Record 类型而不是 Map,因为否则错误的键(mymap.get("concrete3")())会在运行时被发现为异常。

abstract class AbstractFoo {
    abstract foo(): number;
  }

  class Concrete1 extends AbstractFoo {
    foo() {
      return 1;
    }
  }

  class Concrete2 extends AbstractFoo {
    foo() {
      return 2;
    }
  }

  const myMap: Record<string, () => AbstractFoo> = {
    "concrete1": () => new Concrete1(),
    "concrete2": () => new Concrete2(),
  };

  const instantiatedConcrete1 = myMap.concrete1();

  let fooResult = instantiatedConcrete1.foo();

如评论中所述,请注意我使用了工厂模式来创建对象。

这被认为是一个好的设计模式,但在不需要时,基于构造函数的更简单的解决方案可能更合适:

const myRec: Record<string, new() => AbstractFoo> = {
  "concrete1": Concrete1,
  "concrete2": Concrete2,
};

const iConcrete1 = new myRec.concrete1();

语法 new() => AbstractFoo 定义了一个构造函数的签名,该构造函数不接受任何参数,并返回具有 AbstractFoo 结构的对象。

答案#2

据我所知,唯一可用的类型是 typeof AbstractFoo,也就是构造函数类型。就像 typeof Array 指的是 Array 构造函数的类型,而 Array 类型指的是数组实例的类型。

Both Concrete1 和 Concrete2 扩展了该类型(更准确地说,typeof Concrete1 和 typeof Concrete2 扩展了 typeof AbstractFoo)

但你不能创建如下地图:

const myMap: Map<string, typeof AbstractFoo> = new Map()
myMap.set('concrete1string', Concrete1)
myMap.set('concrete2string', Concrete2)

不,你可以,但 myMap.get('concrete1string') 的返回类型是 typeof AbstractFoo,而不是 typeof Concrete1。你不能用 new 调用 typeof AbstractFoo 类型的构造函数。