Mixins
A big flaw of inheritance in the world of OOP is that it is limited to one level. This means you cannot extend more than a single class which can get messy quickly as you end up with large classes that have multiple responsibilities.
TypeScript has something called mixins. They act somewhat like traits in PHP, with the major difference being that under the hood they extend an object and return that. The result of that is rather than simply adding some methods, a completely new object is created that contains the old and new methods.
Mixins are a powerful tool to make use of composition over inheritance but they should be used with caution, as with everything, or you’ll end up with the same issues that come with the excessive use of inheritance.
Prerequisites
Before we start we need to establish what a few recurring variables and imports in this document refer to when they are used.
1import { app } from "@arkecosystem/core-kernel";
- The
app
import refers to the application instance which grants access to the container, configurations, system information and more.
Mixins Usage
1import { app } from "@arkecosystem/core-kernel"; 2 3// Class we will extend through a mixin 4class Block {} 5 6// Function that serves as mixin 7function Timestamped<TBase extends Constructor>(Base: TBase) { 8 return class extends Base { 9 timestamp = new Date("2019-09-01");10 };11}12 13// Types14type AnyFunction<T = any> = (...input: any[]) => T;15type Mixin<T extends AnyFunction> = InstanceType<ReturnType<T>>;16type TTimestamped = Mixin<typeof Timestamped>;17type MixinBlock = TTimestamped & Block;18 19// Register the Mixin20app21 .get<Services.Mixin.MixinService>(Container.Identifiers.MixinService)22 .set("timestamped", Timestamped);23 24// Apply the mixin25const block: MixinBlock = new (26 app27 .get<Services.Mixin.MixinService>(Container.Identifiers.MixinService)28 .apply<MixinBlock>("timestamped", Block)29)();30 31// Ensure the mixin did its job32console.log(block.timestamp === new Date("2019-09-01"));