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

Roy*_*son 7 abstract-class class factory-method abstract typescript

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

我有一个具有以下方法的抽象类(简化):

playAnimation() {
    let animator =  this.createAnimator(this.animatorData)  
    await animator.animate()
}
Run Code Online (Sandbox Code Playgroud)

Create animator 在该抽象类中有以下定义:

abstract createAnimator(animatorData: Object): Animator
Run Code Online (Sandbox Code Playgroud)

子类可能会createAnimator这样实现:

createAnimator(animatorData: StandardAnimatorData) {
    return new RiverAnimator(animatorData.addMessage, animatorData.assetsDir) 
}
Run Code Online (Sandbox Code Playgroud)

或者像这样:

createAnimator(animatorData: StandardAnimatorData) {
    return new BridgeAnimator(animatorData.addMessage, animatorData.assetsDir) 
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的 - 两个子类的实现createAnimator大致相同,除了返回的类型之外Animator

SidenoteBridgeAnimatorRiverAnimator两者都实现了Animator接口,但如果解决方案需要Animator是一个抽象类,我可以更改它。

有没有办法进入createAnimator抽象基类?

理想情况下,抽象类应该有一个抽象变量,它是应该返回的类的类型createAnimator。子类只会实现该变量。然后createAnimator使用该变量返回正确的类型Animator

Mat*_*hen 5

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

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;
}
Run Code Online (Sandbox Code Playgroud)

但我不清楚这是否比createAnimatorSubOuterClass1和中实现更好SubOuterClass2


Ant*_*ton 5

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

宣言:

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

调用:

let animator = this.createAnimator(BridgeAnimator, animatorData);
await animator.animate();
Run Code Online (Sandbox Code Playgroud)