typescript tricky grammar in mixins

Viewed 57
type Constructor<T> = new (...args: any[]) => T;

function f1<T extends {}>(naked: Constructor<T>): any {
    return class dressed extends naked { } // error
}

function f2<T extends Constructor<{}>>(naked: T): any {
    return class dressed extends naked { } // ok
}

f1 says 'dressed' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.

i don't think there is any semantic fault in f1, but why there is a grammar fault?

1 Answers

What is confusing is the Constructor<T> type because, indeedn we can never specify its generic argument T in the class mixin syntax.

With a simpler/non generic definition, we can naturally choose to write a class mixin like f2:

type Constructor = new (...args: any[]) => any;

function Dressed<T extends Constructor>(Base: T) { // Note: no `: any` return type so that the type inference works.
  return class extends Base {}
}

If we need elsewhere a generic Constructor type, we can still specify a default type to keep writing <T extends Constructor> which is les misleading:

type Constructor<T = {}> = new (...args: any[]) => T;
Related