Is it possible to constrain a generic type T to the set of subtypes of type K not including K? I am trying to define a type for inheritance based mixin functions. Question 32488309 provides an answer for the opposite, and coincidentally this question is asked but unanswered in the comments.
// Define a type for the constructor signature.
interface IConstructor { new(...args: any[]): any; }
type Mixin = <T extends IConstructor, U extends T>(Base: T) => U;
// Mix a set of mixins.
function mix(...mixins: Mixin[]) {
return mixins.reduce((child: IConstructor, mixer) => mixer(child), Object);
}
// Mix typically accepts Mixins with the same constructor signature.
interface ILocalized extends IConstructor {
new(i18n: I18n): any;
}
function mixinOne(Base: ILocalized) {
return class MixinOne extends Base {
constructor(i18n: I18n) { super(i18n); }
}
}
This results in the following error from question 56505560 which explains that I have achieved the opposite of my goal. T cannot be the set of subtypes of K, because once it is MixinOne it can't be any other.
const LocalizedBase: IBase = mix(mixinOne, ...);
'typeof MixinOne' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IConstructor'.
Alternatively, the following settles the error, but includes K despite the use of extends.
export type Mixin = (Base: IConstructor) => IConstructor;
I am not interested in the property iterating alternative solution for mixins, because these classes require dependency injection.