-
Notifications
You must be signed in to change notification settings - Fork 12.8k
[Regression] TS2562 - mixins cannot accept generic types #24122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
So I saw recently this issue: #26154 The bug comes probably from here #17829 with this commit #17922 (@ahejlsberg) @RyanCavanaugh explains that it is intentional but in fact it's a regression as everything was working as expected before the 2.6.0 The example I provided is a typical example and often used in mixin:
Currently it's no more possible to do My projects (and probably some of others developers) are stuck to pre 2.6.0 due to this regression. This would be super to re-enable this type of mixin 🥇 |
Another pseudo example to understand the problem: class B {
b: number;
}
function CMixin<TBase extends Constructor<any>>(base: TBase) {
// NOTE the generic type for the mixin class
return class C<T> extends base {
c: T;
constructor(...args: any[]) {
super(args);
}
}
}
// should have a way to provide T from A to the mixin
class A<T> extends <T>CMixin<Constructor<B>>(B) {
constructor() {
super();
}
} But I would prefer to be able to pass T directly to the mixin as it was allowed before |
Here is my simplified use-case: function ContainerMixin<TModel>(baseClass: Constructor<any> = Object) {
return class extends baseClass {
model: TModel;
};
}
interface ModelA {
foo: string;
}
interface ModelB {
bar: string;
}
// Throws an error "Base class expressions cannot reference class type parameters"
class Container<TModel> extends ContainerMixin<TModel>() {}
const containerForModelA = new Container<ModelA>();
// `model` property should have type `ModelA`
containerForModelA.model = {foo: 'bar'};
const containerForModelB = new Container<ModelB>();
// `model` property should have type `ModelB`
containerForModelB.model = {bar: 'baz'}; Currently I have to workaround it by implementing a container class for each type of model: class ContainerForA extends ContainerMixin<ModelA>() {}
class ContainerForB extends ContainerMixin<ModelB>() {} So it's not an ideal solution. |
Are there any plans to change this behavior in future? Currently it prevents using mixins with generic type arguments when creating web components. See example: declare function ComboBoxMixin<P, T extends new (...args: any[]) => {}>(
base: T
): T & ComboBoxMixinConstructor<P>;
interface ComboBoxMixinConstructor<T> {
new (...args: any[]): ComboBoxMixin<T>;
}
interface ComboBoxMixin<T> {
items: Array<T> | undefined;
}
// Error: "Base class expressions cannot reference class type parameters"
declare class ComboBoxElement<T> extends ComboBoxMixin<T>(HTMLElement) {
} |
I have found an elegant workaround to this problem: https://github.com/lifaon74/traits#assembletraitimplementations -> see I migrated the |
@lifaon74 But I fully agree that this problem needs to be solved, otherwise mixins are largely useless for generic classes. |
@Remirror-zz My mixin function looks like this: interface MixedClasses<A, B> extends ClassA<A>, ClassB<B>, ... {
}
interface MixedClassesConstructor {
new<A, B>(...args: any[]): MixedClasses<A, B>;
}
function mixin<GConstructor>(...classes): GConstructor {
// code...
}
class ChildClass<A, B> extends mixin<MixedClassesConstructor>(ClassA, ClassB)<A, B> {
} Note that the generics comes after the So yes, we loose the interface MixedClassesConstructor<A, B> {
new(...args: any[]): MixedClasses<A, B>;
} which is less correct (the generics should come after |
TypeScript Version: 2.6.0 and more
Search Terms: mixin, 2.6.
Code
Expected behavior:
Like before typescript 2.6.0, extending a class with a mixin which takes generic types should be allowed.
Using mixin is a really common usage in js/ts to build classes which implement/inherit properties from more than one classe (sometimes named 'factories'). Before 2.6.0, typescript properly detected the union of class having generic types, but currently this generates TS2562 errors, so its no more possible to construct typed generic mixins.
In a more generic way:
Actual behavior:
TS2562, Base class expression cannot reference class type parameters (on T and U)
Playground Link: here
Related Issues: Partially related #19668
The text was updated successfully, but these errors were encountered: