Decorators zijn speciale annotaties die het gedrag van klassen, eigenschappen, methoden of parameters kunnen wijzigen door middel van aanvullende metadata of het vervangen van implementaties.
Normaal gesproken worden ze gebruikt voor afhankelijkheidsinjectie, logging, validatie, caching of om metadata bekend te maken voor frameworks zoals Angular.
Voorbeeld van een eenvoudige methode-decorator:
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; } }
Valkuilen:
experimentalDecorators is ingeschakeld in tsconfig.Vraag: "Kun je parameters van een decorator zodanig typeren dat je het type van de methode waarop deze wordt toegepast garandeert?"
Antwoord: In de meeste gevallen is typificatie niet mogelijk op het moment van de toepassing van de decorator vanwege de dynamische aard van metaprogrammering. Echter, via generics en aanvullende runtime-controles kan validatie worden toegevoegd, maar de TypeScript-compiler geeft geen garantie op het moment van declaratie van de structuur.
Voorbeeld:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // De compiler garandeert niet dat de methode een number retourneert
Verhaal
In een project met veel decorators op services werd de volgorde van toepassing vergeten: property-decorators werden vóór alle parameters toegepast, wat resulteerde in verlies van Inject-metadata en het onvermogen om afhankelijkheden tijdens runtime op te lossen.
Verhaal
Ontwikkelaars besloten decorators op gewone functies toe te passen, in plaats van op klassemethoden, en waren verrast door de compileerfouten en het ontbreken van runtime-effect. In de TypeScript-specificatie worden decorators alleen toegepast op klassen en hun leden.
Verhaal
Na de versie-updates van TypeScript en experimentele instellingen viel het hele mechanisme van decorators in de aangepaste DI-container uit elkaar: het bleek dat de nieuwe versie expliciete ondersteuning voor Reflect-metadata vereiste, anders ging alle metadata verloren.