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:
- 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 {}
- 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.