Декораторы — это специальные аннотации, которые позволяют изменять поведение классов, свойств, методов или параметров через дополнительную метаинформацию или подмену реализации.
Обычно используют для внедрения зависимостей, логирования, валидации, кеширования или объявления метаданных для фреймворков типа Angular.
Пример простого декоратора метода:
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; } }
Подводные камни:
experimentalDecorators в tsconfig.Вопрос: "Можно ли типизировать параметры декоратора таким образом, чтобы гарантировать тип метода, к которому он применяется?"
Ответ: В большинстве случаев типизация невозможна на этапе применения декоратора из-за динамического характера метапрограммирования. Однако через generics и дополнительные runtime-проверки можно добавить валидацию, но компилятор TypeScript не даст гарантии на этапе декларирования структуры.
Пример:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // Компилятор не гарантирует, что метод возвращает number
История
В проекте с большим количеством декораторов на сервисах забыли про порядок применения: property-декораторы применились до всех параметров, что повлекло потерю Inject-метаданных и невозможность разрешить зависимости во время выполнения.
История
Разработчики решили применить декораторы к обычным функциям, а не методам класса, и были удивлены ошибками компиляции и отсутствием runtime-эффекта. В спецификации TypeScript декораторы применяются только к классам и их членам.
История
После обновления версий TypeScript и экспериментальных настроек сломался весь механизм декораторов в кастомном DI-контейнере: оказалось, новая версия требует явной поддержки Reflect-metadata, иначе вся метаинформация терялась.