It is a commonly used JavaScript/TypeScript strategy to extend a class with new properties and methods.
A good approach to apply mixins is defining them as sub-class factories. Then declare the new mixed class as:
class MixedClass extends MixinFoo(MixinBar(BaseClass)) {}
Check the article, “Real” Mixins with JavaScript Classes, to learn more about it.
Define a Mixin
By defining a mixin, you create a mixin function that takes in a base class, and returns a new class extending the base class with new properties and methods mixed to it.
For example, you have a simple controller which only has a greeter function prints out ‘hi!’:
class SimpleController {
constructor() {}
greet() {
console.log('hi!');
}
}
Now let’s add two mixins to it:
-
A time stamp mixin that adds a property
createdAt
to a record when a controller instance is created. -
A logger mixin to provide logging tools.
Define mixin TimeStampMixin
:
import {MixinTarget} from '@loopback/core';
import {Class} from '@loopback/repository';
export function TimeStampMixin<T extends MixinTarget<object>>(baseClass: T) {
return class extends baseClass {
// add a new property `createdAt`
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
public createdAt: Date;
constructor(...args: any[]) {
super(args);
this.createdAt = new Date();
}
printTimeStamp() {
console.log('Instance created at: ' + this.createdAt);
}
};
}
And define mixin LoggerMixin
:
import {MixinTarget} from '@loopback/core';
import {Class} from '@loopback/repository';
function LoggerMixin<T extends MixinTarget<object>>(baseClass: T) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return class extends baseClass {
// add a new method `log()`
log(str: string) {
console.log('Prints out a string: ' + str);
}
};
}
Note:
A TypeScript limitation prevents mixins from
overriding existing members of a base class. Hence the need for // @ts-ignore
as shown above. See the
API docs for
more info.
Now you can extend SimpleController
with the two mixins:
import {TimeStampMixin} from '../mixins/time-stamp.mixin.ts';
import {LoggerMixin} from '../mixins/logger.mixin.ts';
class SimpleController {
constructor() {}
greet() {
console.log('hi!');
}
}
class AdvancedController extends LoggerMixin(
TimeStampMixin(SimpleController),
) {}
// verify new method and property are added to `AdvancedController`:
let aControllerInst = new AdvancedController();
aControllerInst.printTimeStamp();
// print out: Instance created at: Tue Oct 17 2017 22:28:49 GMT-0400 (EDT)
aControllerInst.logger('hello world!');
// print out: Prints out a string: hello world!
References
Here are some articles explaining ES2015 and TypeScript mixins in more details: