如何在抽象 class return 子实例 classes 的打字稿中使用函数

How to have a function in an abstract class return instances of a child classes in typescript

是否可以有这样的伪代码:

abstract class AbstractParent {
    protected value: number;
    constructor(value: number) {
        this.value = value;
    }
    ...
    public times(multiplicator: number) {
        return new ???(value * multiplicator);
    }
}

returns class Foo extends AbstractParent 的新 Fooclass Bar extends AbstractParent 的新 Bar

一种可维护的方法是将 times 计算保留在基础 class 中,并在 FooBar 中实现单独的 create 工厂方法。这样,基础 class 就不知道其扩展子 classes.

您在 AbstractParent 中将 create 声明为 abstract 以确保它将在所有子 class 中实现。 polymorphic this return type ensures for the caller of times, that the returned instance has the same sub class type (Playground).

abstract class AbstractParent {
    protected value: number;

    constructor(value: number) {
        this.value = value;
    }

    times(multiplicator: number) {
        return this.create(this.value * multiplicator);
    }

    // factory method creates instances of same polymorphic type (Foo / Bar)
    protected abstract create(value: number): this
}

class Foo extends AbstractParent {

    create(value: number) {
        // Polymorphic this type is Foo here, so it's OK to return a Foo.
        // Compiler is not aware of the class context, so we cast. 
        return new Foo(value) as this
    }
}

class Bar extends AbstractParent {
    // same as Foo
    create(value: number) {
        return new Bar(value) as this
    }
}

const foo = new Foo(42).times(2) // Foo
const bar = new Bar(42).times(3) // Bar

您可以将 child 类型传递给 parent 构造函数并保存引用。这样可以避免 parent 必须了解所有可能的 child 类型(尽管我同意另一个答案,即可能有更好的方法来实现您的总体目标)。像这样 (playground link):

type ChildConstructor<Child> = new (value: number, childConstructor: ChildConstructor<Child>) => Child;

abstract class AbstractParent<Child extends AbstractParent<Child>> {
    protected value: number;
    protected childConstructor: ChildConstructor<Child>;

    constructor(value: number, childConstructor: ChildConstructor<Child>) {
        this.value = value;
        this.childConstructor = childConstructor;
    }

    public times(multiplicator: number): Child {
        return new this.childConstructor(this.value * multiplicator, this.childConstructor);
    }
}

class Foo extends AbstractParent<Foo> {
    constructor(value: number) {
        super(value, Foo);
    }
}

class Bar extends AbstractParent<Bar> {
    constructor(value: number) {
        super(value, Bar);
    }
}

请注意,要获得 100% 的类型安全性,每个 child class 都需要至少一个额外的私有 属性 或方法来防止 TypeScript 的 "duck typing"考虑到 classes 是可以互换的(因为它们共享相同的属性和方法)。