Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript definition for ES6 mixins

Tags:

Is there a way to write a Typescript definition for an ES6 mix-in?

I've this pattern in library.js, and I'd like to create the library.d.ts

// declaration in `library.js`
class Super extends Simple {
    constructor() {}

    static Compose(Base = Super) {
        return class extends Base {
            // ...    
        }

    }
}

// usage in `client.js`
class MyClass extends Super.Compose() {}
let myInstance = new MyClass();

class MyOtherClass extends Super.Compose(AnotherClass) {}
like image 315
trefeater Avatar asked Sep 10 '16 20:09

trefeater


1 Answers

No, Typescript type system is not expressive enough for that - see the discussion in https://github.com/Microsoft/TypeScript/issues/7225 and https://github.com/Microsoft/TypeScript/issues/4890.

The idiomatic 'type of classes' in typescript is written as

interface Constructor<T> {
    new (...args): T;
}

So one way to write declaration for Compose is

export declare class Simple {}

export declare class Super extends Simple {
    static Compose<T>(Base?: Constructor<T>): Constructor<T & {/*mixed-in declarations*/}>
}

That is, Compose return type is declared to be a constructor for intersection type - a type which must have all the properties of parameter (Base) together with all the properties of the mixin.

You can use that declaration (assuming it's in the library.d.ts file) like this

import {Super} from './library'

let MyComposed = Super.Compose(Super)
let myInstance = new MyComposed

The minor inconvenience is that you always have to provide argument for Super.Compose() because type inference does not work without knowing the value for default parameter, and you can't provide value for default parameter in the declaration file.

But the big problem is that you can't really use the result of Compose as a class:

class MyClass extends Super.Compose(Super) {}

does not compile due to the issues mentioned above:

error TS2509: Base constructor return type 'Super & {}' is not a class or interface type.
like image 63
artem Avatar answered Sep 24 '22 14:09

artem