如何在抽象类中具有函数以TypeScript返回子类的实例

时间:2019-11-05 08:16:17

标签: typescript inheritance abstract-class parent-child extends

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

class Article(models.Model):
    code = models.CharField(max_length=20, blank=False, default='0216')
    designation = models.CharField(max_length=200, blank=False)
    unit = models.CharField(max_length=10, choices=choices_unite, default='')
    quantity = models.FloatField(default=0)
    quantity_in_stock = models.FloatField(default=0)


    def __str__(self):
        return self.designation

class ProductionArticle(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    planned quantity = models.FloatField(default=0)
    production date = models.DateTimeField(default=timezone.now, verbose_name="Date d'ajout")
    unit = models.CharField(max_length=10, choices=choices_unite, default='')
    operator = models.CharField(max_length=200, default='Ahmed')
    quantity_prod  = models.FloatField(defaut=0)

哪个返回abstract class AbstractParent { protected value: number; constructor(value: number) { this.value = value; } ... public times(multiplicator: number) { return new ???(value * multiplicator); } } 的新Fooclass Foo extends AbstractParent的新Bar

2 个答案:

答案 0 :(得分:1)

一种可维护的方法是将times计算保留在基类中,并在createFoo内实现单独的Bar工厂方法。这样,基类不知道其扩展子类。

您在create中将abstract声明为AbstractParent,以确保它将在所有子类中实现。 polymorphic this返回类型为times的调用者确保返回的实例具有相同的子类类型(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

答案 1 :(得分:0)

您可以将子类型传递给父构造函数并保存引用。这样可以避免父母必须了解所有可能的孩子类型(尽管我同意另一个答案,即可能有更好的方法来实现您的总体目标)。像这样(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%的类型安全性,每个子类都需要至少具有一个附加的私有属性或方法,以使TypeScript的“鸭子类型”不被视为可互换类(因为它们共享相同的属性和方法) )。