-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Generic return value of a mixin constructor #22431
Comments
Two things, a mixin constructor needs to have a So your interface Constructor<I extends Instance> {
new(...args: any[]): I;
}
function MixIn<T extends Constructor<Instance>>(Base: T) {
return class extends Base {
}
} if you want to capture the type of the instance you can use |
thanks for your answer. In my case the Mixin is just for a special Base because the added functonality uses functions from that class. So I used the real class interface (the added functionality at my example makes no sense here, it is just to show what I mean): function MixIn<T extends mongoose.Document, M extends mongoose.Model<T>>(Base: M) {
return class extends Base {
static findByName(name: string): Promise<T> {
return this.find({name: name});
}
} I think that does not work because your argument " a mixin constructor needs to have a ...args in it's signature". The interface Model<T extends mongoose.Document> {
new(...args: any[]): T;
// copied from @types/mongoose/index.d.ts
find(callback?: (err: any, res: T[]) => void): mongoose.DocumentQuery<T[], T>;
find(conditions: any, callback?: (err: any, res: T[]) => void): mongoose.DocumentQuery<T[], T>;
find(conditions: any, projection?: any | null,
callback?: (err: any, res: T[]) => void): mongoose.DocumentQuery<T[], T>;
find(conditions: any, projection?: any | null, options?: any | null,
callback?: (err: any, res: T[]) => void): mongoose.DocumentQuery<T[], T>;
}
function MixIn<T extends mongoose.Document, M extends Model<T>>(Base: M) {
return class extends Base {
static findByName(name: string): Promise<T> {
return this.find({name: name});
}
} That didn't work too. But as I changed the return value of the interface to The only disadvantage: I have to copy the interface to get the required interface with the Also thanks for the hint with |
You don't need to write your own Example: class Foo {
constructor(a: string) {}
}
function MyMixin<C extends new (...args: any[]) => {}>(Base: C) {
return class extends Base {
mixinMethod() {}
}
}
class Bar extends MyMixin(Foo) {}
} |
You're right, your example works. But you've removed my requirement, that I want to call a function of the Base class. To show it, I add it to your example: class Foo {
constructor(a: string) {}
doSomething() {}
}
function MyMixin<C extends new (...args: any[]) => {}>(Base: C) {
return class extends Base {
mixinMethod() {
this.doSomething(); // ERROR Property 'doSomething' does not exist on type '(Anonymous class)'.
}
}
}
class Bar extends MyMixin(Foo) {} Now I get an error because the C extends new (...args: any[]) => {doSomething(): void} But now I'm rewriting the model interface, because a |
@Xenya0815 You shouldn't do
Does that work? |
ahh, you got me! you're right with instance methods. That works like a charm. so once again: class Foo {
static doSomething() {}
constructor(a: string) {}
}
function MyMixin<C extends new (...args: any[]) => {}>(Base: C) {
return class extends Base {
static mixinMethod() {
this.doSomething(); // Property 'doSomething' does not exist on type '{ new (...args: any[]): (Anonymous class); prototype: MyMixin<any>.(Anonymous class); mixinMethod...'
}
}
}
class Bar extends MyMixin(Foo) {} When I change the base class declaration to: C extends { new(...args: any[]): {}; doSomething(): void } It works again. Do you have a better solution for here without to define the required methods manually? |
@Xenya0815 How about doing You can do |
Sure, I could use the Base directly like class Foo {
static doSomething() {}
constructor(a: string) {}
}
class ExtendedFoo extends Foo {
static doSomething() {
console.log('doSomething was called');
super.doSomething();
}
}
function MyMixin<C extends { new(...args: any[]): {}; doSomething(): void }>(Base: C) {
return class extends Base {
static mixinMethod() {
this.doSomething(); // with log
Foo.doSomething(); // without log
}
}
}
class Bar extends MyMixin(ExtendedFoo) {} |
@Xenya0815 I see what you mean; that's a bummer. I devised a weird hack, does this work? function MyMixin<C extends typeof Foo>(Base: C) {
return (<C2 extends Constructor<Foo>>(_base: C2) => {
return class extends _base {
static mixinMethod() {
Base.doSomething(); // with log
Foo.doSomething(); // without log
}
}
})(Base);
}
|
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
TypeScript Version: 2.8.0-dev.20180308
Code
Expected behavior:
That my MixIn accepts that construct so that I can define a extended interface T with properties which are available at a instance of the MixIn class.
Actual behavior:
It works when I remove the generic type at the function
MixIn
(likefunction MixIn(Base: Constructor<Instance>)
) .Related Issues:
I found old issues like #8853 or #4890
Because that I thought it should work.
The text was updated successfully, but these errors were encountered: