Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mix into abstract base class in Typescript

I would like to mix in some methods to an abstract base class, to make a new abstract class.

Take the following example:

abstract class Base {
    abstract method();
}

interface Feature {
    featureMethod();
}

class Implementation extends Base implements Feature {
    method() {
    }

    featureMethod() {
       // re-usable code that uses method() call
       this.method();
    }
}

This works fine, but the goal is to take the implementations of the Feature interface and move it to a mixin so it can be re-used by other implementations of the Base class.

I have got to the following, but it doesn't compile in Typescript 2.4.1

type BaseConstructor<T = Base > = new (...args: any[]) => T;
export function MixFeature<BaseType extends BaseConstructor>(TheBase: BaseType) {
    abstract class Mixed extends TheBase implements Feature {
        featureMethod() {
            // re-usable code that uses method() call
            this.method();
        }
    }
    return Mixed;
}

class Implementation extends MixFeature(Base) {
    method() {
    }
}

But Typescript does not approve, saying:

Error:(59, 41) TS2345:Argument of type 'typeof Base' is not assignable to parameter of type 'BaseConstructor<Base>'.
Cannot assign an abstract constructor type to a non-abstract constructor type.

Is it possible to make this work or is it a Typescript limitation that abstract bases cannot be extended using mixins?

like image 595
tul Avatar asked Nov 19 '25 11:11

tul


1 Answers

There is currently no way to describe the type of an abstract class constructor in TypeScript. GitHub Issue Microsoft/TypeScript#5843 tracks this. You can look in there for ideas. One suggestion is that you can suppress the error by simply asserting that Base is a BaseConstructor:

// no error
class Implementation extends MixFeature(Base as BaseConstructor) {
    method() {
    }
}

Now your code compiles. But note that since there is no way to specify that BaseConstructor represents an abstract constructor, the returned class will be interpreted as concrete whether you want it to or not, despite the fact that Mixed is declared as abstract:

// also no error; may be surprising
new (MixFeature(Base as BaseConstructor));

So for now you'll just have to be careful if you want to use mixins with abstract classes. Good luck!

like image 107
jcalz Avatar answered Nov 21 '25 10:11

jcalz