ProgrammazioneFullstack разработчик

Как работает декоратор типов (Decorator) в TypeScript? Для чего их используют, как реализовать кастомный декоратор, и какие подводные камни встречаются при работе с ними?

Supera i colloqui con l'assistente IA Hintsage

Ответ.

Декораторы — это специальные аннотации, которые позволяют изменять поведение классов, свойств, методов или параметров через дополнительную метаинформацию или подмену реализации.

Обычно используют для внедрения зависимостей, логирования, валидации, кеширования или объявления метаданных для фреймворков типа 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.
  • Несовместимы с некоторыми настройками strict mode.
  • Декораторы не всегда вызываются в том порядке, в каком ожидается; важно понимать стек вызовов.
  • Декораторы на параметрах не позволяют изменить их значения напрямую.

Вопрос с подвохом.

Вопрос: "Можно ли типизировать параметры декоратора таким образом, чтобы гарантировать тип метода, к которому он применяется?"

Ответ: В большинстве случаев типизация невозможна на этапе применения декоратора из-за динамического характера метапрограммирования. Однако через generics и дополнительные runtime-проверки можно добавить валидацию, но компилятор TypeScript не даст гарантии на этапе декларирования структуры.

Пример:

function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // Компилятор не гарантирует, что метод возвращает number

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В проекте с большим количеством декораторов на сервисах забыли про порядок применения: property-декораторы применились до всех параметров, что повлекло потерю Inject-метаданных и невозможность разрешить зависимости во время выполнения.


История

Разработчики решили применить декораторы к обычным функциям, а не методам класса, и были удивлены ошибками компиляции и отсутствием runtime-эффекта. В спецификации TypeScript декораторы применяются только к классам и их членам.


История

После обновления версий TypeScript и экспериментальных настроек сломался весь механизм декораторов в кастомном DI-контейнере: оказалось, новая версия требует явной поддержки Reflect-metadata, иначе вся метаинформация терялась.