GitHub
Prototyppackages/mixin-class-factory/src

Mixin Class Factory

@ralphschuler/mixin-class-factory

Komponiert Fähigkeiten mehrerer Klassen, ohne eine tiefe Einzelvererbungshierarchie aufzubauen.

compositiondecoratorsconfig

01 · Problem

Wofür braucht man das?

Mehrere orthogonale Fähigkeiten sollen in einer Klasse zusammenkommen, obwohl TypeScript nur eine Basisklasse erlaubt.

02 · Denkmodell

Das mentale Modell

Ein Mixin ist eine Transformation von Basisklasse zu erweiterter Basisklasse. Config-Schemas werden zusammengeführt, Konflikte vor der Instanziierung entschieden.

Im Repository

Decorators speichern Config- und Interface-Metadaten; createClass kopiert nur enumerable Own-Properties der Mixin-Instanzen. Prototype-Methoden, Defaults und InterfaceMethod-Metadaten werden nicht übernommen.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Mixin-Verträge und Config-Schemas einsammeln.
  2. Namens- und Typkonflikte vor der Klassenerzeugung erkennen.
  3. Defaults in eine neue Config kopieren, vollständig validieren und erst dann einfrieren.
  4. Prototype-Descriptors oder standardmäßige Class-Mixin-Ketten anwenden.

04 · Bauteile

Die entscheidenden Verträge

ConfigProperty(type, defaultValue) Legacy-Decorator für erwartete Configfelder; Default wird aktuell nicht angewendet.
InterfaceMethod() Sammelt Methodennamen, die createClass nicht auswertet.
createClass(...mixins) Erzeugt asynchron einen Konstruktor und kopiert nur Instanzfelder.

05 · Build it yourself

Selbst implementieren

Bevorzuge TypeScript-Class-Mixins; sie erhalten Methoden und Typinformation ohne Runtime-Reflection.

  1. Definiere ein gemeinsames Constructor-Generic.
  2. Jedes Mixin gibt eine Unterklasse der erhaltenen Basis zurück.
  3. Komponiere Mixins explizit und behandle Config über normale Konstruktorparameter.
minimal.ts · unabhängig vom Package
type Constructor<T = object> = new (...args: any[]) => T;

const WithLogging = <B extends Constructor>(Base: B) =>
  class extends Base {
    log(message: string) { console.log(message); }
  };

const WithId = <B extends Constructor>(Base: B) =>
  class extends Base { readonly id = crypto.randomUUID(); };

class Empty {}
class Service extends WithLogging(WithId(Empty)) {}

06 · Verifizieren

Was du testen solltest

  • Komponierte Instanzen besitzen Methoden und Felder aller Mixins.
  • Konfliktstrategie für gleiche Methodennamen ist festgelegt und getestet.
  • Config-Defaults, ungültige Typen und unveränderte Eingabeobjekte werden geprüft.

07 · Grenzen

Kompromisse und Stolperfallen

  • Mixin-Ketten können komplexe Constructor- und Generic-Typen erzeugen.
  • Runtime-Komposition braucht Property-Descriptors und verliert oft instanceof-Semantik.
Wichtig

Object.assign einer Instanz kopiert keine normalen Klassenmethoden, weil diese auf dem Prototype liegen und nicht enumerable sind.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen