NestJS — стремительно набирающий популярность фрeймворк, построенный на идеях IoC/DI, модульного дизайна и декораторов. Благодаря последним, Nest имеет лаконичный и выразительный синтаксис, что повышает удобство разработки. Декораторы или аннотации — наследники аспектов, которые позволяют декларативно описывать логику, модифицировать поведение классов, их свойств, аргументов и методов. Технически декораторы — это просто функции, но их вызовом полностью управляет компилятор.
Важная особенность заключается в том, что в зависимости от контекста, сигнатуры аргументов будут различаться. Материалов на эту тему существует довольно много, однако мы сосредоточимся на специфике, связанной непосредственно с Nest. Возьмем простейший http-контроллер. Допустим, нам требуется, чтобы только определенные пользователи могли воспользоваться его методами. Для этого кейса в Nest есть встроенная функциональность гардов. Guard — это комбинация класса, реализующего интерфейс CanActivate и декоратора @UseGuard. Захардкоженный superuser — не самое лучшее решение, куда чаще нужны более универсальные декораторы.  Nest в этом случае предлагает использовать декоратор @SetMetadata. Как понятно из названия, он позволяет ассоциировать метаданные с декорируемыми объектами — классами или методами. Для доступа к этим данным используется экземпляр класса Reflector, но можно и напрямую через reflect-metadata. Декораторы зачастую применяются в связках. Обычно это обусловлено тесной связностью эффектов в каком-то бизнес-сценарии. В этом случае имеет смысл объединить несколько декораторов в один. Для композиции можно воспользоваться утилитной функцией applyDecorators. или написать агрегатор самим: Легко столкнуться с ситуацией, когда оказывается нужным задекорировать все методы класса. Такой код можно сделать чище, если повесить декоратор на сам класс. И уже внутри декоратора класса обойти прототип, применяя эффекты на все методы, как если бы декораторы были повешены на каждый метод по-отдельности. Однако для этого обработчику необходимо различать типы объектов применения — класс и метод — и в зависимости от этого выбирать поведение. Реализация декораторов в typescript не содержит этот признак в явном виде, поэтому его приходится выводить из сигнатуры вызова. Есть вспомогательные библиотеки, которые берут на себя часть этой рутины: lukehorvat/decorator-utils, qiwi/decorator-utils.
Это несколько улучшает читаемость. Совмещение в одном декораторе логики для разных сценариев дает очень весомый плюс для разработки:
вместо @DecForClass, @DecForMethood, @DecForParam получается всего один многофункциональный @Dec. Так, например, если роль пользователя вдруг потребуется в бизнес-слое контроллера, можно просто расширить логику @Role. Добавляем в ранее написанную функцию обработку сигнатуры декоратора параметра.
Так как подменить значение параметров вызова напрямую нельзя, createParamDecorator делегирует это вышестоящему декоратору посредством метаданных.  И далее именно декоратор метода / класса будет резолвить аргументы вызова (через очень длинную цепочку от ParamsTokenFactory до RouterExecutionContext). Также стоит отметить, что при помощи метадаты можно решать разные интересные кейсы, например, вводить ограничения для повторяемости или сочетаемости аннотаций. Предположим, нам потребовалось ограничение размера запроса, и соответствующий декоратор повесили дважды. Какому значению доверять? Без знания логики компилятора возникает неопределенность. Правильнее, наверное, было бы бросить ошибку. Вот другой пример: необходимо ограничить работу методов контроллера отдельными портами. Здесь, скорее, требуется не затирать предыдущие значения, а добавлять новые к имеющимся. Схожая ситуация возникает с ролевой моделью. Обобщая рассуждения, реализация декоратора для последнего примера с использованием reflect-metadata и полиморфного контракта может иметь вид: Nest спроектирован таким образом, что его собственные декораторы удобно расширять и переиспользовать. На первый взгляд довольно сложные кейсы, к примеру, связанные с добавлением поддержки новых протоколов, реализуются парой десятков строк обвязочного кода. Так, стандартный @Controller можно «обсахарить»
для работы с JSON-RPC.
Не будем останавливаться на этом подробно, это слишком бы далеко вышло за формат этой статьи, но покажу основную идею: на что способны декораторы, в сочетании с Nest. Далее необходимо извлечь @Req() из rpc-method в мидлваре, найти совпадение с метой, которую добавил декоратор @JsonRpcMethod.  Готово, можно использовать: Декораторы Nest адаптируются к широкому спектру прикладных задач. В них легко переносится утилитная и бизнесовая логика. Их несложно расширять, композировать, совмещая несколько сценариев. И в этом, без сомнения, одна из сильных сторон фреймворка. Однако важно помнить, что синтаксис декораторов сегодня все еще является экспериментальным, а их чрезмерное использование может дать обратный эффект, и сделать ваш код более запутанным.