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.
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?
- Mixin-Verträge und Config-Schemas einsammeln.
- Namens- und Typkonflikte vor der Klassenerzeugung erkennen.
- Defaults in eine neue Config kopieren, vollständig validieren und erst dann einfrieren.
- 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.
- Definiere ein gemeinsames Constructor-Generic.
- Jedes Mixin gibt eine Unterklasse der erhaltenen Basis zurück.
- Komponiere Mixins explizit und behandle Config über normale Konstruktorparameter.
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.
Object.assign einer Instanz kopiert keine normalen Klassenmethoden, weil diese auf dem Prototype liegen und nicht enumerable sind.
08 · Weiterdenken