来自 Ruby:如何在 TypeScript 中将静态方法移动到抽象 class?

Coming from Ruby: How to move a static method into abstract class in TypeScript?

我有两个 classes,每个都有一个方法 build returns 相应 class:

的一个新实例
class Foo {
  static build() {
    return new Foo();
  }
}

class Bar {
  static build() {
    return new Bar();
  }
}

实际的实现比较复杂。但是,我试图通过将实现移至抽象 class 来消除重复,但我不知道如何实现它:

abstract class Base {
  static build() {
    return // <- ???
  }
}

class Foo extends Base {
}

class Bar extends Base {
}

此外,我希望能够在 Foo 和/或 Bar:

中覆盖 build
class Bar extends Base {
  static build() {
    instance = super(); // <- couldn't get this working
    // do something with instance
    return instance;
  }
}

也许我的方法完全错误。在 Ruby 中,我会写:

module M
  def build
    new
  end
end

class Foo
  extend M
end

class Bar
  extend M
end

并覆盖 build:

class Bar
  extend M
  def self.build
    instance = super
    # do something with instance
    instance
  end
end

我怎样才能在 TypeScript 中实现这些目标?

也许是这样的?

abstract class Base
{
    protected static build(cls: {new(): Base}): Base
    {
        // common init logic comes here
        return new cls();
    }
}

class Foo extends Base
{
    static build(): Foo
    {
        const instance = Base.build(Foo);
        // do something specific with instance
        return instance;
    }
}


class Bar extends Base
{
    static build(): Bar
    {
        const instance = Base.build(Bar);
        // do something specific with instance
        return instance;
    }
}


const foo = Foo.build();
const bar = Bar.build();

@Amid 的回答很好,只有一个问题是如果 FooBar 有它们自己的任何属性,那么您将遇到编译器错误,因为只有 Base.build returns Base。你可以引入一个类型参数来解决这个问题:

abstract class Base {

    protected static build<T>(cls: { new (): T }): T {
        // common init logic comes here
        return new cls();
    }
}

此外,当将 class 传递给 Base.build 时,您可以只传递 this,因为静态方法中的 this 将引用当前的 class :

class Foo extends Base {

    static build(): Foo {
        const instance = Base.build(this); // `instance` will be typed as `Foo` instead of `Base`
        // do something specific with instance
        return instance;
    }
}

[我在这里回答我自己的问题]

查看生成的 JavaScript 后,我意识到在调用超类上的方法时已经传递了 this

获得正确的类型要困难得多。这最终对我有用:

interface BaseConstructor<T> {
  new(): T;
  build(): T;
}

abstract class Base {
  static build<T extends Base>(this: BaseConstructor <T>): T {
    return new this(); // <- this is either Foo or Bar
  }
}

class Foo extends Base {
}

class Bar extends Base {
}

Foo.build(); // instance of Foo
Bar.build(); // instance of Bar