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

configuration.mddocs/

Configuration

Global configuration settings for controlling mixin behavior. The settings object allows you to customize how ts-mixer handles prototype mixing, static properties, constructor initialization, and decorator inheritance.

Capabilities

Settings Object

Global configuration object that controls ts-mixer behavior across all mixin operations.

/**
 * Global settings object for configuring ts-mixer behavior
 * Changes affect all subsequent mixin operations
 */
interface Settings {
  /** Name of init function to call after construction, null to disable */
  initFunction: string | null;
  /** Strategy for handling static properties: 'copy' or 'proxy' */  
  staticsStrategy: "copy" | "proxy";
  /** Strategy for mixing prototypes: 'copy' or 'proxy' */
  prototypeStrategy: "copy" | "proxy";
  /** Decorator inheritance strategy: 'deep', 'direct', or 'none' */
  decoratorInheritance: "deep" | "direct" | "none";
}

/**
 * Global settings instance - modify properties to change behavior
 */
declare const settings: Settings;

Configuration Options

Prototype Strategy

Controls how class prototypes are mixed together.

import { settings } from "ts-mixer";

// Copy strategy (default) - better performance, ES5 compatible
settings.prototypeStrategy = "copy";

// Proxy strategy - dynamic updates, ES6+ only  
settings.prototypeStrategy = "proxy";

Copy Strategy ("copy"):

  • Pros: Better performance, ES5 compatible, no proxy overhead
  • Cons: Static references - changes to base class prototypes after mixing aren't reflected
  • Use when: Performance is critical, you don't modify prototypes after mixing

Proxy Strategy ("proxy"):

  • Pros: Dynamic - updates to base classes are reflected in mixed classes
  • Cons: Slower property access, requires ES6+ Proxy support
  • Use when: You need dynamic prototype updates, prototype methods change at runtime
import { Mixin, settings } from "ts-mixer";

class Base {
  getValue(): string {
    return "original";
  }
}

class Other {
  getOther(): string {
    return "other";
  }
}

// Test copy strategy
settings.prototypeStrategy = "copy";
class CopyMixed extends Mixin(Base, Other) {}

const copyInstance = new CopyMixed();
console.log(copyInstance.getValue()); // "original"

// Modify base class after mixing
Base.prototype.getValue = () => "modified";

console.log(copyInstance.getValue()); // Still "original" - not updated

// Test proxy strategy  
settings.prototypeStrategy = "proxy";
class ProxyMixed extends Mixin(Base, Other) {}

const proxyInstance = new ProxyMixed();
console.log(proxyInstance.getValue()); // "modified" - dynamically updated

Statics Strategy

Controls how static properties and methods are inherited.

import { settings } from "ts-mixer";

// Copy strategy (default)
settings.staticsStrategy = "copy";

// Proxy strategy
settings.staticsStrategy = "proxy";

Copy Strategy ("copy"):

  • Copies all static properties at mixin creation time
  • Changes to base class statics after mixing aren't reflected
  • Better performance for static property access

Proxy Strategy ("proxy"):

  • Proxies static property access to base classes
  • Dynamic updates to base class statics are reflected
  • Slightly slower static property access
import { Mixin, settings } from "ts-mixer";

class BaseClass {
  static baseStaticProp: string = "base";
  static baseStaticMethod(): string {
    return "base method";
  }
}

class OtherClass {
  static otherStaticProp: string = "other";
}

// Test copy strategy
settings.staticsStrategy = "copy";
class CopyMixed extends Mixin(BaseClass, OtherClass) {}

console.log(CopyMixed.baseStaticProp); // "base"
console.log(CopyMixed.baseStaticMethod()); // "base method"

// Modify base class static after mixing
BaseClass.baseStaticProp = "modified base";

console.log(CopyMixed.baseStaticProp); // Still "base" - not updated

// Test proxy strategy
settings.staticsStrategy = "proxy";  
class ProxyMixed extends Mixin(BaseClass, OtherClass) {}

console.log(ProxyMixed.baseStaticProp); // "modified base" - dynamically updated

Init Function

Specifies a function name to call after construction with proper this context.

import { settings } from "ts-mixer";

// Enable init function (disabled by default)
settings.initFunction = "init";

// Disable init function
settings.initFunction = null;

Purpose: ES6 constructor limitations prevent ts-mixer from passing the correct this to constructors. The init function workaround allows constructor-like behavior with proper this context.

Usage Pattern:

import { Mixin, settings } from "ts-mixer";

settings.initFunction = "init";

class Person {
  public static allPeople: Set<Person> = new Set();
  
  name: string;
  
  constructor(name: string) {
    this.name = name;
    // Cannot use 'this' for side effects here in mixins
  }
  
  // Init function receives proper 'this' context
  protected init(name: string) {
    Person.allPeople.add(this); // This works correctly
  }
}

class Employee {
  public static allEmployees: Set<Employee> = new Set();
  
  employeeId: number;
  
  constructor(name: string, employeeId: number) {
    this.employeeId = employeeId;
  }
  
  protected init(name: string, employeeId: number) {
    Employee.allEmployees.add(this); // This works correctly
  }
}

class PersonEmployee extends Mixin(Person, Employee) {}

// Both constructors and both init functions are called
const emp = new PersonEmployee("John Doe", 12345);

console.log(Person.allPeople.has(emp)); // true - init function worked
console.log(Employee.allEmployees.has(emp)); // true - init function worked
console.log(emp.name); // "John Doe" - constructor worked
console.log(emp.employeeId); // 12345 - constructor worked

Init Function Features:

  • Called with the same arguments passed to the constructor
  • Receives proper this context (unlike constructors in mixins)
  • All init functions from mixed classes are called in order
  • Optional - only classes that define the init function participate

Decorator Inheritance

Controls how decorators are inherited during mixing.

import { settings } from "ts-mixer";

// Deep inheritance (default) - inherit from all ancestors
settings.decoratorInheritance = "deep";

// Direct inheritance - only from direct mixin classes
settings.decoratorInheritance = "direct";

// No inheritance - disable decorator inheritance
settings.decoratorInheritance = "none";

Deep Inheritance ("deep"):

  • Inherits decorators from all classes in the prototype chain
  • Includes decorators from ancestor classes of mixed classes
  • Most comprehensive decorator inheritance

Direct Inheritance ("direct"):

  • Only inherits decorators from classes directly passed to Mixin()
  • Ignores decorators from ancestor classes
  • More predictable decorator behavior

None ("none"):

  • Disables decorator inheritance completely
  • Fastest option when decorators aren't needed
  • Use for better performance when decorators aren't used
import { Mixin, decorate, settings } from "ts-mixer";

function MyDecorator(name: string) {
  return function(target: any) {
    target.decoratorApplied = name;
  };
}

@decorate(MyDecorator("grandparent"))
class GrandParent {}

@decorate(MyDecorator("parent"))
class Parent extends GrandParent {}

@decorate(MyDecorator("mixin"))
class MixinClass {}

// Deep inheritance
settings.decoratorInheritance = "deep";
class DeepMixed extends Mixin(Parent, MixinClass) {}
// Inherits decorators from: GrandParent, Parent, MixinClass

// Direct inheritance  
settings.decoratorInheritance = "direct";
class DirectMixed extends Mixin(Parent, MixinClass) {}
// Inherits decorators from: Parent, MixinClass (not GrandParent)

// No inheritance
settings.decoratorInheritance = "none";
class NoDecorators extends Mixin(Parent, MixinClass) {}
// Inherits no decorators

Configuration Examples

Performance-Optimized Configuration

import { settings } from "ts-mixer";

// Optimize for performance
settings.prototypeStrategy = "copy";      // Faster property access
settings.staticsStrategy = "copy";        // Faster static access  
settings.decoratorInheritance = "none";   // Skip decorator processing
settings.initFunction = null;             // Skip init function calls

// Use for high-performance scenarios where you don't need:
// - Dynamic prototype updates
// - Dynamic static updates  
// - Decorator inheritance
// - Init function workarounds

Dynamic Update Configuration

import { settings } from "ts-mixer";

// Optimize for dynamic behavior
settings.prototypeStrategy = "proxy";     // Dynamic prototype updates
settings.staticsStrategy = "proxy";       // Dynamic static updates
settings.decoratorInheritance = "deep";   // Full decorator inheritance
settings.initFunction = "init";           // Enable init functions

// Use when you need:
// - Runtime modifications to base classes
// - Full decorator support
// - Constructor workarounds

Balanced Configuration

import { settings } from "ts-mixer";

// Balanced approach (default settings)
settings.prototypeStrategy = "copy";      // Good performance
settings.staticsStrategy = "copy";        // Good performance
settings.decoratorInheritance = "deep";   // Full decorator support
settings.initFunction = null;             // Disabled by default

// Good for most use cases providing:
// - Reasonable performance
// - Full decorator inheritance  
// - Simple constructor behavior

Runtime Configuration Changes

Settings can be changed at runtime and affect all subsequent mixin operations:

import { Mixin, settings } from "ts-mixer";

// Initial setting
settings.prototypeStrategy = "copy";

class A {}
class B {}

class Mixed1 extends Mixin(A, B) {} // Uses copy strategy

// Change setting
settings.prototypeStrategy = "proxy";

class Mixed2 extends Mixin(A, B) {} // Uses proxy strategy

// Mixed1 still uses copy, Mixed2 uses proxy

Important Notes:

  • Settings changes don't affect already-created mixed classes
  • Each mixin operation uses the current settings at the time of creation
  • Consider setting configuration early in your application lifecycle

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