I can't get the code following to type-check:
type MyFunctionConstructor<T, F extends MyFunction<T>> = new (
f: (n: number) => T
) => F;
class MyFunction<T> {
constructor(f: (n: number) => T) {
this.f = f;
}
f: (n: number) => T;
composeT(g: (t: T) => T) {
return new (this.constructor as MyFunctionConstructor<T, this>)(n =>
g(this.f(n))
);
}
composeU<U>(g: (t: T) => U) {
return new (this.constructor as MyFunctionConstructor<U, this>)(n =>
g(this.f(n)) // tsc error here, see below
);
}
}
class MyFancyFunction<T> extends MyFunction<T> {}
I get the following error:
Type 'this' does not satisfy the constraint 'MyFunction<U>'.
Type 'MyFunction<T>' is not assignable to type 'MyFunction<U>'.
Type 'T' is not assignable to type 'U'.
I don't want to call the constructor by name (i.e., new MyFunction(...)) so that if f is an instance of a subclass of MyFunction (e.g., of FancyFunction) then so are f.composeT(g) and f.composeU(g). The as casting used for the constructor call in composeT isn't working for the more general composeU method that has a generic parameter. How can I deal with the extra generic, U?
(The method for making composeT type-check is comes from this answer. This question is essentially a follow-up that I couldn't fit in a comment.)