Decoratoren sind spezielle Annotations, die es ermöglichen, das Verhalten von Klassen, Eigenschaften, Methoden oder Parametern durch zusätzliche Metainformationen oder Implementierungsveränderungen zu ändern.
Sie werden normalerweise zur Abhängigkeitsinjektion, Protokollierung, Validierung, Caching oder zur Deklaration von Metadaten für Frameworks wie Angular verwendet.
Beispiel eines einfachen Methodendecorators:
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Call: ${propertyKey}(${JSON.stringify(args)})`); return original.apply(this, args); }; } class Example { @Log doSomething(a: number, b: number) { return a + b; } }
Fallstricke:
experimentalDecorators in tsconfig aktiviert ist.Frage: "Kann man die Parameter eines Decorators so typisieren, dass man den Typ der Methode garantiert, auf die er angewendet wird?"
Antwort: In den meisten Fällen ist eine Typisierung zur Zeit der Anwendung des Decorators aufgrund der dynamischen Natur der Metaprogrammierung nicht möglich. Durch Generics und zusätzliche Laufzeitprüfungen kann jedoch eine Validierung hinzugefügt werden, aber der TypeScript-Compiler bietet keine Garantie zum Zeitpunkt der Deklaration der Struktur.
Beispiel:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // Der Compiler garantiert nicht, dass die Methode eine Zahl zurückgibt
Geschichte
In einem Projekt mit vielen Decoratoren in Services wurde die Reihenfolge der Anwendung vergessen: Property-Decorator wurden vor allen Parametern angewendet, was zum Verlust von Inject-Metadaten und der Unmöglichkeit führte, Abhängigkeiten zur Laufzeit aufzulösen.
Geschichte
Entwickler versuchten, Decoratoren auf normalen Funktionen anstelle von Klassenmethoden anzuwenden und waren überrascht von Kompilierungsfehlern und dem Fehlen von Laufzeiteffekten. In der TypeScript-Spezifikation werden Decoratoren nur auf Klassen und deren Mitglieder angewendet.
Geschichte
Nach Aktualisierungen der TypeScript-Versionen und experimentellen Einstellungen brach der gesamte Decoratorenmechanismus in einem benutzerdefinierten DI-Container zusammen: Es stellte sich heraus, dass die neue Version eine explizite Unterstützung für Reflect-metadata erforderte, ansonsten gingen alle Metainformationen verloren.