A TypeScript library that provides tolerable Mixin functionality with multiple inheritance support.
—
Core mixin functionality for creating classes that inherit from multiple base classes. The Mixin function is the primary way to combine multiple classes into a single class.
Creates a new class that inherits properties and methods from multiple base classes.
/**
* Creates a new class by mixing multiple classes together
* Supports up to 10 classes with full type inference
*/
function Mixin<A extends any[], I1, S1>(
c1: Class<A, I1, S1>
): Class<A, I1, S1>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>
): Class<Longest<A1, A2>, I1 & I2, S1 & S2>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>
): Class<Longest<A1, A2, A3>, I1 & I2 & I3, S1 & S2 & S3>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>
): Class<Longest<A1, A2, A3, A4>, I1 & I2 & I3 & I4, S1 & S2 & S3 & S4>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>
): Class<Longest<A1, A2, A3, A4, A5>, I1 & I2 & I3 & I4 & I5, S1 & S2 & S3 & S4 & S5>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5,
A6 extends any[], I6, S6
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>,
c6: Class<A6, I6, S6>
): Class<Longest<A1, A2, A3, A4, A5, A6>, I1 & I2 & I3 & I4 & I5 & I6, S1 & S2 & S3 & S4 & S5 & S6>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5,
A6 extends any[], I6, S6,
A7 extends any[], I7, S7
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>,
c6: Class<A6, I6, S6>,
c7: Class<A7, I7, S7>
): Class<Longest<A1, A2, A3, A4, A5, A6, A7>, I1 & I2 & I3 & I4 & I5 & I6 & I7, S1 & S2 & S3 & S4 & S5 & S6 & S7>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5,
A6 extends any[], I6, S6,
A7 extends any[], I7, S7,
A8 extends any[], I8, S8
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>,
c6: Class<A6, I6, S6>,
c7: Class<A7, I7, S7>,
c8: Class<A8, I8, S8>
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5,
A6 extends any[], I6, S6,
A7 extends any[], I7, S7,
A8 extends any[], I8, S8,
A9 extends any[], I9, S9
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>,
c6: Class<A6, I6, S6>,
c7: Class<A7, I7, S7>,
c8: Class<A8, I8, S8>,
c9: Class<A9, I9, S9>
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8, A9>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8 & I9, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 & S9>;
function Mixin<
A1 extends any[], I1, S1,
A2 extends any[], I2, S2,
A3 extends any[], I3, S3,
A4 extends any[], I4, S4,
A5 extends any[], I5, S5,
A6 extends any[], I6, S6,
A7 extends any[], I7, S7,
A8 extends any[], I8, S8,
A9 extends any[], I9, S9,
A10 extends any[], I10, S10
>(
c1: Class<A1, I1, S1>,
c2: Class<A2, I2, S2>,
c3: Class<A3, I3, S3>,
c4: Class<A4, I4, S4>,
c5: Class<A5, I5, S5>,
c6: Class<A6, I6, S6>,
c7: Class<A7, I7, S7>,
c8: Class<A8, I8, S8>,
c9: Class<A9, I9, S9>,
c10: Class<A10, I10, S10>
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8 & I9 & I10, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 & S9 & S10>;Usage Examples:
import { Mixin } from "ts-mixer";
// Basic mixin with two classes
class Disposable {
isDisposed: boolean = false;
dispose() {
this.isDisposed = true;
}
}
class Activatable {
isActive: boolean = false;
activate() {
this.isActive = true;
}
deactivate() {
this.isActive = false;
}
}
class SmartObject extends Mixin(Disposable, Activatable) {
interact() {
this.activate();
console.log("Interacting with active object");
}
}
const obj = new SmartObject();
obj.activate();
obj.dispose();
console.log(obj.isActive, obj.isDisposed); // true, true
// Mixing classes that extend other classes
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Mammal extends Animal {
warmBlooded: boolean = true;
}
class Flyable {
fly() {
return "Flying!";
}
}
class Bat extends Mixin(Mammal, Flyable) {
constructor(name: string) {
super(name);
}
hunt() {
return `${this.name} is ${this.fly().toLowerCase()} and hunting`;
}
}
const bat = new Bat("Vampire Bat");
console.log(bat.hunt()); // "Vampire Bat is flying! and hunting"
console.log(bat.warmBlooded); // true
// Mixing abstract classes (requires TypeScript 4.2+)
abstract class Shape {
abstract getArea(): number;
}
abstract class Named {
abstract getName(): string;
}
class Circle extends Mixin(Shape, Named) {
constructor(private radius: number, private name: string) {
super();
}
getArea(): number {
return Math.PI * this.radius * this.radius;
}
getName(): string {
return this.name;
}
}
const circle = new Circle(5, "My Circle");
console.log(`${circle.getName()}: ${circle.getArea()}`);When mixing classes, ts-mixer creates instances of each base class and copies their properties to the mixed instance. This means:
this may not work as expectedsettings.initFunction) for this-dependent side effectssettings.staticsStrategyStatic properties and methods from all base classes are inherited by the mixed class, subject to the configured strategy:
'copy' strategy: Static properties are copied at mixin creation time'proxy' strategy: Static property access is proxied to base classesThe Mixin function will throw errors in the following scenarios:
When using proxy strategies, additional errors may be thrown:
Install with Tessl CLI
npx tessl i tessl/npm-ts-mixer