Please note: This page is a work-in-progress. It may have errors and is subject to change.

Introduction

Along with traditional OO hierarchies, another popular way of building up classes from reusable components is to build them by combining simpler partial classes. You may be familiar with the idea of mixins or traits for languages like Scala, and the pattern has also reached some popularity in the JavaScript community.

Mixin sample

In the code below, we show how you can model mixins in TypeScript. After the code, we'll break down how it works.

// Disposable Mixin
class Disposable {
    isDisposed: boolean;
    dispose() {
        this.isDisposed = true;
    }
 
}
 
// Activatable Mixin
class Activatable {
    isActive: boolean;
    activate() {
        this.isActive = true;
    }
    deactivate() {
        this.isActive = false;
    }
}
 
class SmartObject implements Disposable, Activatable {
    constructor() {
        setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
    }
 
    interact() {
        this.activate();
    }
 
    // Disposable
    isDisposed: boolean = false;
    dispose: () => void;
    // Activatable
    isActive: boolean = false;
    activate: () => void;
    deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable])
 
var smartObj = new SmartObject();
setTimeout(() => smartObj.interact(), 1000);
 
////////////////////////////////////////
// In your runtime library somewhere
////////////////////////////////////////

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        })
    }); 
}

Understanding the sample

The code sample starts with the two classes that will act is our mixins. You can see each one is focused on a particular activity or capability. We'll later mix these together to form a new class from both capabilities.

// Disposable Mixin
class Disposable {
    isDisposed: boolean;
    dispose() {
        this.isDisposed = true;
    }
 
}
 
// Activatable Mixin
class Activatable {
    isActive: boolean;
    activate() {
        this.isActive = true;
    }
    deactivate() {
        this.isActive = false;
    }
}

Next, we'll create the class that will handle the combination of the two mixins. Let's look at this in more detail to see how it does this:

class SmartObject implements Disposable, Activatable {

The first thing you may notice in the above is that instead of using 'extends', we use 'implements'. This treats the classes as interfaces, and only uses the types behind Disposable and Activatable rather than the implementation. This means that we'll have to provide the implementation in class. Except, that's exactly what we want to avoid by using mixins.

To satisfy this requirement, we create stand-in properties and their types for the members that will come from our mixins. This satisfies the compiler that these members will be available at runtime. This lets us still get the benefit of the mixins, albeit with a some bookkeeping overhead.

// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;

Finally, we mix our mixins into the class, creating the full implementation.

applyMixins(SmartObject, [Disposable, Activatable])

Lastly, we create a helper function that will do the mixing for us. This will run through the properties of each of the mixins and copy them over to the target of the mixins, filling out the stand-in properties with their implementations.

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        })
    }); 
}

Last edited Dec 21, 2013 at 9:22 PM by jonturner, version 10

Comments

mindplay Sep 23, 2014 at 11:29 AM 
Any progress on "real" mixins?

The type system does a great job at mirroring most type patterns in JS, all except mixins - which unfortunately are very common in JS.

Without it the type system remains incomplete - that is, we're still one step short of being able to describe JavaScript mixin type patterns.

Duplication and interfaces are not the answer, because this does not reflect what's actually happening in JavaScript - e.g. not duplication, but type "decoration" of sorts.

Any hope for adding this feature in the future?

mindplay Mar 25, 2014 at 11:19 PM 
Jon,

This is interesting only as a proof of concept - in practice, this approach is not really useful.

I attempted to port [observable.js](https://github.com/mindplay-dk/riotjs/blob/master/lib/observable.js) to TypeScript and essentially gave up - having to write dummy boilerplate implementations of every method in every implemented interface negates the value of using mixins for something like this, since every class ends up repeating the entire interface declaration in the form of dummy methods.

What we need, is either:

1. Some kind of ambient declaration that permits you to say "this class implements that interface", without actually making you implement it, or

2. A new keyword that does essentially the same thing, e.g. permitting something along the lines of `class Foo extends Bar implements Baz uses MyMixin`, where `uses` (or some other keyword) means "the class does implement this interface, but it happens at run-time, and TypeScript does not need to know how."

I was really hoping to see this feature added prior to 1.0.

serendipitic Feb 27, 2014 at 12:34 PM 
I have an Interface that contains overloaded methods:

interface Mixin {
preValidate(attr: any): any;
preValidate(attr: string, value: string): any;
}

At some point, an external library adds the methods defined by the Interface to my class. Therefore, I want to add those methods to my class using "implements Mixin". However, if I put those standins (that re mentioned in this article) into my class, I get an error that I have a duplicate identifier:

preValidate: (attr: any) => any;
preValidate: (attr: string, value: string) => any;

Any suggestions on how to implement this are much appreciated! :-)

nabog Dec 16, 2013 at 7:01 PM 
Very useful start to addressing mixins.

Worth noting the following are prohibited:

1. The mixin type cannot have any private fields or methods.
2. The mixin fields cannot be initialised to a default value - such initialisation needs to occur in the "SmartObject.