Understanding Mixins in TypeScript

Fernando Doglio
Bits and Pieces
Published in
6 min readJun 17, 2020

--

Image by Gerd Altmann from Pixabay

One of the limitations imposed by TypeScript when it comes to class inheritance is that you can only extend a single class at a time. In most normal cases this is not a problem, but if you’re working with a complex enough architecture, you might find yourself a bit constrained by the language.

Let’s look at an example: pretend you have the need to encapsulate two different behaviors into two different abstract classes: Callable and Activable

Since we’re just making things up at this point, let’s say they both add a single method to the derived class, allowing you to either call the object or activate it (whatever that might mean for you). Remember, these are abstract classes because the added behavior is completely independent of the derived class. The normal thing to do, would be something like this:

Ofcourse, like I said before, TypeScript won’t allow us to do that, check out the following image to see the error we would get.

In order to fix this we can do a simple (and really nasty) workaround, which is to chain the inheritance. Or in other words, make Callable extend Activable, and MyClass extend Callable. That would definitely solve our little problem, but at the same time, it would force Callable to always extend Activable. This is a very bad design pattern and one you should avoid at all costs, there is a reason why you wanted to have both behaviors separate, so it makes no sense to force them together like that.

A fun and powerful way to reuse components

Bit (GitHub) helps you effectively build, reuse, and manage components.

It’s a fun and powerful way to collaborate on components across projects — to speed up, scale, and improve application development. It’s everything you need from local development to mastering changes in your different apps.

Create your own powerful component lib on Bit.dev

Get standard tools to develop and publish many components in any project, enjoy a stunning cloud collection with visual docs, and streamline component reuse across developers and applications. Found something you like shared by a teammate? Use or even update the component right in any new project!

Join thousands of teams already using Bit to accelerate and standardize development with components. Try the component cloud for free.

Mixins to the rescue!

So what can we do? Here is where mixins come into play. Now, mixins aren’t a special construct provided by TypeScript, instead they’re more of a technique that takes advantage of two different aspects of the language:

  • Declaration merging, which is a very strange and implicit behavior you need to be aware of.
  • Interface class extension, which means interfaces in TS can extend several classes at the same time, unlike classes themselves.

Essentially the steps to make this work are:

  1. Add the method signatures from the parent classes to our derived class
  2. Iterate over the methods of the parent classes and for every method that both, the parent and the derived class have, manually link them together.

I know, it sounds complicated, but actually, it’s not THAT hard, all you have to remember is how to achieve both of those points and you’re done.

And in order to understand what’s going on, let’s start by number two first:

TypeScript’s official documentation site already provides the function for us to use, so let’s not really try to re-invent the wheel here:

The function above is just iterating over the parent classes, and for each one, iterating over its list of properties and defining those properties into the derived class. Essentially we’re manually linking all methods and properties from the parents into the child.

An interesting side note: notice how when we have to deal with the inner workings of classes, we’re actually referencing the prototype chain directly. This is a clear sign that the new class model of JavaScript is, like I mentioned before, more syntactic sugar than anything else.

With this out of the way, if we try to use it, we’ll run into the problem shown below, this is because although we’ve done our part, and we’ve added the missing methods to the child class, we’re still dealing with TypeScript, who’s actively checking the shape of our objects to make sure we’re calling the right methods, and although we added the methods, we didn’t really change the shape of MyClass (i.e we didn’t really declare the right relationship).

And here is where declaration merging and interface class extension come into place.

And that’s it! But let me explain, because it took me several tries to understand it myself.

  1. The MyClass definition is now only a single class definition that is not really extending anything.
  2. I’ve added a new interface definition, with the exact same name as the class we’re creating. This is crucial, because this interface is extending both abstract classes, thus merging their method definition into a single construct (the interface) which at the same time, is getting merged into the class definition because they have the same name (i.e declaration merging, meaning interfaces can be merged into classes — and other constructs — if they have the same name).

Now, MyClass’ definition has the method signatures we need and the correct shape, thus we’re now free to use the applyMixins function with our classes and properly call the newly added methods:

This code would result in our expected output. Remember, now that you’ve endured the process of understanding how mixins work, I’ve given you a completely reproducible formula you can use for all your classes. Just copy & paste the function, and remember to properly declare the interface and you’ll be done!

Conclusion

I hope the explanation was clear enough, Mixins are conceptually an easy thing to understand, but the code can get messy at times.

This article is part of a book about Deno I’m currently writing, so if you want to know more about Deno and how TypeScript fits with it, you can read more about that project over here.

Now let me ask you, have you had the need to create mixins in the past? Or were you able to work with TypeScript’s limitation of extending from a single class? Let me know down in the comments!

Publish and Reuse React Components with Bit

Bit makes it easy to publish reusable React components from any project to Bit’s component hub.

Need to update a published component? bit import it into your project, change it, and push it back with a bumped version.

Share components with your team to maximize code reuse, speed up delivery and build apps that scale.

Example: exploring React components published on Bit.dev

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/