Typescript - 将 Class 类型存储为变量,以便从中创建对象或其他等效功能

Typescript - Store Class Type As Variable In Order to Create Objects From It Or Other Equivalent Functionality

前言 - 我在 SO 上看过与此类似的帖子,但答案似乎不适用。

我有一个摘要class,方法如下(简化):

playAnimation() {
    let animator =  this.createAnimator(this.animatorData)  
    await animator.animate()
}

Create animator 在该摘要中有以下定义 class:

abstract createAnimator(animatorData: Object): Animator

子class 可能会像这样实现 createAnimator

createAnimator(animatorData: StandardAnimatorData) {
    return new RiverAnimator(animatorData.addMessage, animatorData.assetsDir) 
}

或者像这样:

createAnimator(animatorData: StandardAnimatorData) {
    return new BridgeAnimator(animatorData.addMessage, animatorData.assetsDir) 
}

如您所见 - classes 的两个子 createAnimator 实现大致相同,除了 Animator 的类型是 returned。

旁注 BridgeAnimatorRiverAnimator 都实现了 Animator 接口,但是如果解决方案要求 Animator 是抽象的 class,我可以更改它。

有没有办法将createAnimator移动到抽象基础class中?

理想情况下,抽象 class 应该有一个抽象变量,它是 createAnimator 应该 return 的 class 的类型。 Subclasses 只会实现该变量。然后 createAnimator 将使用该变量 return Animator.

的正确类型

是的,你可以这样做(我制作了一个大代码片段,以便我可以验证所有内容是否编译):

interface Animator {
  animate(): Promise<void>;
}

class RiverAnimator implements Animator {
  async animate() { }
  constructor(addMessage: unknown, assetsDir: unknown) { }
}
class BridgeAnimator implements Animator {
  async animate() { }
  constructor(addMessage: unknown, assetsDir: unknown) { }
}

interface StandardAnimatorData {
  addMessage: unknown;
  assetsDir: unknown;
}

// Common interface for the constructor functions RiverAnimator and BridgeAnimator 
interface AnimatorConstructor {
  new(addMessage: unknown, assetsDir: unknown): Animator;
}

abstract class AbstractOuterClass {
  abstract animatorConstructor: AnimatorConstructor;
  animatorData: StandardAnimatorData;
  createAnimator(data: StandardAnimatorData) {
    return new this.animatorConstructor(data.addMessage, data.assetsDir);
  } 
  async playAnimation() {
    let animator = this.createAnimator(this.animatorData);
    await animator.animate();
  }
}

class SubOuterClass1 extends AbstractOuterClass {
  animatorConstructor = RiverAnimator;
}

class SubOuterClass2 extends AbstractOuterClass {
  animatorConstructor = BridgeAnimator;
}

但我不清楚这是否比在 SubOuterClass1SubOuterClass2 中实施 createAnimator 更好。

另一种方法是利用泛型的力量:

声明:

createAnimator<T extends Animator>(
    type: { new(addMessage: unknown, assetDir: unknown): T }, 
    animatorData: StandardAnimatorData
): T {
    return new type(animatorData.addMessage, animatorData.assetDir);
}

调用:

let animator = this.createAnimator(BridgeAnimator, animatorData);
await animator.animate();