Dekoratory to specjalne adnotacje, które pozwalają na modyfikację zachowania klas, właściwości, metod lub parametrów poprzez dodatkowe metainformacje lub zastąpienie implementacji.
Zwykle używa się ich do wstrzykiwania zależności, logowania, walidacji, cache'owania lub deklarowania metadanych dla frameworków typu Angular.
Przykład prostego dekoratora metody:
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; } }
Pułapki:
experimentalDecorators w tsconfig.Pytanie: "Czy można typować parametry dekoratora w taki sposób, aby zagwarantować typ metody, do której jest stosowany?"
Odpowiedź: W większości przypadków typowanie jest niemożliwe na etapie zastosowania dekoratora z powodu dynamicznego charakteru metaprogramowania. Jednak za pomocą generics oraz dodatkowych sprawdzeń w czasie wykonywania można dodać walidację, ale kompilator TypeScript nie zapewni gwarancji na etapie deklaracji struktury.
Przykład:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // Kompilator nie gwarantuje, że metoda zwraca number
Historia
W projekcie z dużą ilością dekoratorów w serwisach zapomniano o kolejności zastosowania: dekoratory właściwości zostały zastosowane przed wszystkimi parametrami, co spowodowało utratę metadanych Inject i niemożność rozwiązania zależności w czasie wykonywania.
Historia
Programiści postanowili zastosować dekoratory do zwykłych funkcji, a nie metod klas, i byli zaskoczeni błędami kompilacji oraz brakiem efektu w czasie wykonywania. W specyfikacji TypeScript dekoratory stosowane są tylko do klas i ich członków.
Historia
Po aktualizacji wersji TypeScript i ustawień eksperymentalnych cały mechanizm dekoratorów w niestandardowym kontenerze DI przestał działać: okazało się, że nowa wersja wymaga wyraźnego wsparcia Reflect-metadata, w przeciwnym razie cała metainformacja znika.