Extending multiple classes in TypeScript

Extending multiple classes in TypeScript

If you tried to extend multiple classes, you know you can't do something like

export class ChildClass extends ParentClass, GrandParentClass {}

without getting an error that you can extend only one class

But, you can do something like this

const ExtendedParent = class ParentClass extends GrandParentClass {}
export class ChildClass extends ExtendedParent {}

Now, let's do a mixin that will automagically do the extensions for you, no matter how many classes you need to extend.

class ClassExtenderMixin {
  private superclass: any;

  constructor(superclass: any) {
    this.superclass = superclass;
  }

  with(...otherClassesMixins: any[]) {
    return otherClassesMixins.reduce((extendedClass, classMixin) => classMixin(extendedClass), this.superclass);
  }
}

export default (superclass: any) => new ClassExtenderMixin(superclass);

You call this mixin where you want to extend a class, like so:

import extendClass from 'class.extender.mixin';

export default class ChildClass extends extendClass(ParentClass).with(GrandParentClassMixin, GrandGrandParentClassMixin, etc)

And you need to define the other classes mixin as so:

export default (superclass: any) => class extends superclass { // the content of GrandParentClass } 

What happens with the ClassExtenderMixin is:

  1. when you call extendClass(ParentClass), you make the ParentClass as the superClass of the new returned class; so you have something like:
const ParentClassToExtend = extendClass(ParentClass)
// this translates to
const ParentClassToExtend = new ClassExtenderMixin(ParentClass)

export default ChildClass extends ParentClassToExtend {}
  1. next, you call the ParentClassToExtend with method, which takes the other classes mixins functions with the current class you are passing as arguments; Note that in the with's arguments, you transform the arguments in an array, with the rest parameters and that's why you can call reduce on the method arguments.
// at first iteration, you call the mixin function and assign the extendedClass as
// class extends ParentClass; let's call this ExtendedParentClass
// this happens, because GrandParentClassMixin is defined as (superclass) => class extends superclass {}

// at second iteration, you call the mixin function assign the extendedClass as
// the class extends ExtendedParentClass
// this happens because GrandGrandParentClassMixin is also defined as (superClass) => class extends superclass {}

// and so on, if you have multiple extender mixins

You can use this method for extending an AbstractClass with SomeSpecificMethodsClass and SomeOtherSpecificMethodsClass

Note, I took this pattern from JavaScript. There is also another pattern for extending classes in TypeScript.