Search code examples
typescriptinheritanceabstract-classparent-childextends

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


Is it possible to have something like this pseudocode:

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

Which returns a new Foo for class Foo extends AbstractParent and a new Bar for class Bar extends AbstractParent?


Solution

  • A maintainable way is to keep the times calculation in the base class, and implement separate create factory methods inside Foo and Bar. This way, the base class is not aware of its extending child classes.

    You declare create as abstract in AbstractParent to make sure it will be implemented in all sub classes. The 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