I'm trying to build a mixin function that optionally expects a super class. The rationale is that we often just build intermediate classes to start off with our mixins. I am quite confident with the following declarations, but they don't work, however:
interface Test {
readonly __TEST: "test";
new (...args: any[]): {
readonly test: "test";
};
}
function TestMixin<SuperClass extends new (...args: any[]) => any>(
superClass?: SuperClass
) {
const defaultClass = class {};
/* Error: Type 'new (...args: any[]) => any' is not assignable to type 'SuperClass extends undefined ? typeof defaultClass : undefined'.ts(2322) */
const sc: typeof superClass extends undefined ? typeof defaultClass : undefined = superClass === undefined ? defaultClass : superClass;
/* Error: Type 'SuperClass extends undefined ? typeof defaultClass : undefined' is not a constructor function type. */
class T extends sc implements InstanceType<Test> {
public static readonly __TEST = "test";
public readonly test = "test";
}
return T;
}
You can't extend a conditional type, Typescripts expects the clause in the extends
clause to be a constructor, not any other more complicated type.
I think the simplest solution in this case would be to lie to the compiler with a type assertion:
interface Test {
readonly __TEST: "test";
new(...args: any[]): {
readonly test: "test";
};
}
function TestMixin<SuperClass extends new (...args: any[]) => any = new () => {}>(
superClass?: SuperClass
) {
const defaultClass = class { };
/* ok */
const sc = (superClass === undefined ? defaultClass : superClass) as SuperClass;
/* Ok now */
class T extends sc implements InstanceType<Test> {
public static readonly __TEST = "test";
public readonly test = "test";
}
return T;
}
let a = TestMixin();
new a().test;
let b = TestMixin(class {
constructor(n: number) { console.log("Hi") }
m() { }
});
new b(1).test;
new b(1).m();
As long as nobody specifies an explicit type parameter to TestMixin
and omits the parameter, it should work fine.