4

I've read this article. https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/

here is the original code of JavaScript from the article:

class MyClass extends mix(MyBaseClass).with(Mixin1, Mixin2) {
  /* ... */
}

let mix = (superclass) => new MixinBuilder(superclass);

class MixinBuilder {
  constructor(superclass) {
    this.superclass = superclass;
  }

  with(...mixins) { 
    return mixins.reduce((c, mixin) => mixin(c), this.superclass);
  }
}

I'm wondering how to create such a mixin utility helper in typescript so I can get the type hitting and static code analysis.

I've been tried hours... but couldn't finish it without using some any types, if I use any I miss all the type hints, which is not what I want.

1 Answer 1

6

You can use chaining, since otherwise all Mixins would have to have the same return signature using generics:

interface Ctor<T = NonNullable<any>> {
    new(...params: any[]): T;
}

interface MixIn<Superclass extends Ctor, Extension extends Ctor> {
    (ctor: Superclass): Superclass & Extension;
}
function mix<T>(superclass: Ctor<T>) {
    return new MixinBuilder(superclass);
}

interface Mixed<T extends Ctor> {
    with<K extends Ctor>(mixin: MixIn<T, K>): Mixed<ReturnType<MixIn<T, K>>> & ReturnType<MixIn<T, K>>;
}

class MixinBuilder<T extends Ctor> {
    superclass: T;
    constructor(superclass: T) {
        console.log(superclass);
        this.superclass = superclass;
    }

    with<K extends Ctor>(mixin: MixIn<T, K>): Mixed<ReturnType<MixIn<T, K>>> & ReturnType<MixIn<T, K>>  {
        const mixed = mixin(this.superclass);
        return class extends mixed {
            static with<K extends Ctor>(mixin: MixIn<typeof mixed, K>) {
                return new MixinBuilder(mixed).with(mixin);
            }
        } as any;
    }
}

Playground

Sign up to request clarification or add additional context in comments.

7 Comments

I believe you can add handle more than one argument in with but there will be a different signature required for different params quantity, as many popular libraries do
I know, but since that requires a lot of signatures, I find it easier to just have chaining (since it doesn't add much bloat on the user) - Especially for StackOverflow where some people copy/paste without reading and wonder why it fails at 10+ parameters
Wow,nice work!!!!!! The only pity thing is that you have to manually specify the interface of the returned mixin class. Is there any better solution so the compiler can infer the mixin's interface by itself ?
Thanks man! Actually, I just found that it can not be chained! how sad..
@yaquawa, I fixed the chainability (I forgot the intersection for the Mixed interface)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.