-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Feature request: Support for using mixins inside other mixins. #32004
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
@RyanCavanaugh I've been working away the problems using Here's an example that shows the use of a custom type Constructor<T = object, A extends any[] = any[], Static = {}> = (new (
...a: A
) => T) &
Static;
function Constructor<T = object, Static = {}>(
Ctor: Constructor<any>
): Constructor<T> & Static {
return Ctor as any; // we're confident about this any cast.
}
type MixinResult<
TClass extends Constructor,
TBase extends Constructor
> = Constructor<InstanceType<TClass> & InstanceType<TBase>> & TClass & TBase;
class BaseClass {
foo!: string;
static bar = 123;
}
const base = new BaseClass();
base.bar; // correctly not available here
class Test extends BaseClass {
static bat = "bob";
notStatic = 4;
}
function factory<T extends Constructor<BaseClass>>(cls: T) {
class FactoryResult extends Constructor<BaseClass, typeof BaseClass>(cls) {
bar!: string;
make(): InstanceType<typeof BaseClass> {
return this;
}
}
return FactoryResult as MixinResult<typeof FactoryResult, T>;
}
const factoryResult = factory(Test);
factoryResult.bat; // good, available here
factoryResult.foo; // good, foo is not a static property
factoryResult.bar = 42; // good, bar is static
factoryResult.bar = "blah"; // good, static bar is not a string
const foo = new factoryResult();
foo.notStatic; // good, available here
foo.foo; // good, correctly available
foo.bar = "blah"; // good, instance property bar is defined on line 24.
foo.bar = 42; // good, instance prop bar is not a number
function factoryG<C extends typeof BaseClass>(cls: C) {
return class extends Constructor<BaseClass>(cls) {
foo = 123; // good, we get an error
bar!: string;
};
} The example shows:
|
I updated the above example, to show the full pattern I use (needed?) to have proper mixin classes. |
Oh, right, so back to the main point in the OP: The pattern I just illustrated now makes it possible to compose mixins out of other mixins in an understandable way through use of the function AnotherMixin<C extends Constructor<BaseClass>>(Base: C) {
// compose mixins together
class Another extends factoryG(factory(Constructor<BaseClass>(Base))) {
feeling = 'nice'
}
return Another as MixinResult<typeof Another, C>;
}
class A extends AnotherMixin(Test) {
oh = 'yeah'
} So, to point out the main issue of the OP again, one would think it would be sufficient to write: return class Another extends factoryG(factory(Base)) { but that results in the error
which makes all code that uses We know Would it be possible for TypeScript to just know? |
Closing as duplicate of #32080 |
Search Terms
Suggestion
Based on https://stackoverflow.com/questions/56680049, it seems mixin classes can't be used inside other mixins.
It'd be great if, in that example, the outer mixin would be able to successfully use the props and types from the Sizeable mixin.
Note, in the example,
Sizeable
is a class with a default Base class applied, and.mixin
is the mixin function used to create it.Basically, the following (in JS, and simplified):
So it's just a regular class-factory mixin (with a default application so that it is easy to extend like a normal class when used as a base class).
Use Cases
To be able to use Mixins anywhere, including inside other mixins.
Examples
But actually,
Parent
is a constructor. We know it is. It'd be great to use it.In the Foo mixin, I should at least be able to correctly use Sizeable properties and methods, as if Sizeable were the base class.
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: