I have a rough idea of what the type of mixin functions should be, but I keep getting errors no matter how I approach it. For example, this code works:
class BaseClass {}
type Constructor<T extends BaseClass> = new (...args: any[]) => T;
type Mixin = <T extends BaseClass, U extends T>(Base: Constructor<T>) => Constructor<U>;
const mixins: Array<Mixin> = [];
class Mixer {
private static mixins: Record<string, Mixin> = {};
public static registerMixin(name: string, mixin: Mixin): void {
if (!Mixer.mixins[name]) {
Mixer.mixins[name] = mixin;
}
}
public static getClass(...mixinNames: Array<string>): Constructor<BaseClass> {
let mixedClass = BaseClass;
for (const name of mixinNames) {
if (Mixer.mixins[name]) {
mixedClass = Mixer.mixins[name](mixedClass);
}
}
return mixedClass;
}
}
Mixer.registerMixin('a', Base => class extends Base { public a = '' });
Mixer.registerMixin('b', Base => class extends Base { public b = '' });
Mixer.registerMixin('c', Base => class extends Base { public c = '' });
Mixer.registerMixin('d', Base => class extends Base { public d = '' });
Mixer.registerMixin('e', Base => class extends Base { public e = '' });
console.log(new (Mixer.getClass('a', 'c', 'e'))());
If you copy it to the typescript playground (https://www.typescriptlang.org/play), for example, you will see that the code behaves as you'd expect it to. For each of the Mixer.registerMixin
calls, though, you get these two errors:
Type 'typeof (Anonymous class)' is not assignable to type 'Constructor<U>'.
Type '(Anonymous class)' is not assignable to type 'U'.
'(Anonymous class)' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'BaseClass'.
Class '(Anonymous class)' incorrectly extends base class 'T'.
'(Anonymous class)' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'BaseClass'.
At this point, I am uncertain whether my Mixin type is wrong or whether I need to add annotations somewhere in the Base => class extends Base { /* ... */ }
constructs. Does anybody know how to get rid of the errors?