CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ts-mixer

A TypeScript library that provides tolerable Mixin functionality with multiple inheritance support.

Pending
Overview
Eval results
Files

core-mixing.mddocs/

Core Mixing

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.

Capabilities

Mixin Function

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()}`);

Mixin Behavior

Constructor Handling

When mixing classes, ts-mixer creates instances of each base class and copies their properties to the mixed instance. This means:

  • Each base class constructor is called with the same arguments
  • Constructor side effects involving this may not work as expected
  • Use init functions (configured via settings.initFunction) for this-dependent side effects

Property Copying

  • Instance properties from all base classes are copied to the mixed instance
  • Static properties are handled according to settings.staticsStrategy
  • Getters and setters are properly preserved
  • Protected and private properties are supported

Method Resolution

  • When multiple classes define the same method, the last class in the mixin list takes precedence
  • Method resolution follows the prototype chain of the mixed class
  • Override precedence can be controlled by the order of classes in the mixin call

Static Property Inheritance

Static 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 classes

Error Handling

The Mixin function will throw errors in the following scenarios:

  • Invalid arguments (non-constructor functions)
  • Circular mixin dependencies
  • Memory-related issues with very deep prototype chains

When using proxy strategies, additional errors may be thrown:

  • Cannot set prototype of proxies created by ts-mixer
  • Cannot define new properties on proxies created by ts-mixer
  • Cannot delete properties on proxies created by ts-mixer

Install with Tessl CLI

npx tessl i tessl/npm-ts-mixer

docs

configuration.md

core-mixing.md

decorators.md

generic-classes.md

index.md

mixin-detection.md

tile.json