Декораторы в Typescript
Декораторы похожи на аннотации в JAVA или атрибуты в C#. Они предоставляют определения для класса, свойства или функции. Декораторы предлагаются как часть ECMAScript 7. Декораторы полезны для внедрения дополнительных возможностей в существующие определения без необходимости переписывать или дублировать существующий код.
Чтобы использовать декоратор, нам нужно включить для параметра experimentalDecorators значение true в tsconfig.json. В противном случае при компиляции машинописного текста tsc ‹имя файла появится сообщение об ошибке времени компиляции, показанной ниже. ц›
ошибка TS1219: экспериментальная поддержка декораторов — это функция, которая может быть изменена в будущем выпуске. Установите параметр «experimentalDecorators» в «tsconfig» или «jsconfig», чтобы удалить это предупреждение.
Я столкнулся с этим при разработке микросервиса с использованием Nest js, и становится очень важно понимать их, поскольку они широко используются в экосистеме Nest js. например @UseGuards в Nest js — это пример декоратора метода.
Декораторы можно рассматривать как простые функции с входными параметрами, которые предоставляют определения класса, свойства или функции во время выполнения. Обратите внимание на использование @‹decorator›.
Декораторы вызываются на этапе определения, а не на этапе создания экземпляра. Чтобы лучше понять, давайте посмотрим на этот пример
function simpleDecorator(target:Function) { console.log("I am from simple decorator"); } @simpleDecorator export class ClassType { constructor() { console.log("I am from ctor"); } } let instance = new ClassType(); output: I am from simple decorator I am from ctor
«Я из простого декоратора» выводится в консоли перед «Я из ctor». Мы видим, что декораторы вызываются до создания экземпляров. на самом деле, если мы создадим несколько экземпляров classType, мы увидим, что декораторы вызываются только один раз, когда classType определен.
Хорошо, но почему у нас есть аргумент декоратора как функция, а не другой тип в приведенном выше примере? Это потому, что класс в TS в основном является функцией в Javascript. Если у нас нет типа в качестве функции и он имеет строковый тип, то мы получим ошибку «Аргумент типа ‘тип ClassType’ не может быть назначен параметру типа ‘String’».
Можем ли мы применить несколько декораторов к классу, свойству или функции? Да.
Что, если нам нужно передать параметры декоратору? Для этого мы должны использовать фабрику декораторов. Фабрика декораторов возвращает функцию декоратора, например.
//Decorator factory return a decoratory function function decoratorFactory(paramters: any[]) { return function(ctor:Function) { console.log(`Data passed onto decorator:${paramters}`); } } @decoratorFactory(["param 1", "param 2", "param n"]) export class TargetClass{ }
Типы декораторов
- Класс декораторов.
- Декораторы методов.
- Декораторы недвижимости.
- Декораторы параметров.
Декоратор классов
Все приведенные выше примеры, которые мы видели до сих пор, относятся к декораторам классов. С помощью декораторов на уровне класса мы можем внедрять свойства через прототипы, например.
function Component(targetClass:Function) { //Injecting porperty via decorator. targetClass.prototype.FrmDecoraator = "prototype property set by decorator"; console.log(targetClass.name); //Accessing the name property of the target class Function. console.log((<any>targetClass).StaticProperty); } //class decorator @Component export class TargetClass { static StaticProperty:string ="static property"; constructor() { console.log("I am from ctor"); } } let instanceOfTargetClass= new TargetClass(); //Injected prototype from decorator function into TargetClass console.log((<any>instanceOfTargetClass).FrmDecoraator);
Декораторы свойств:
Декораторы свойств применяются к свойствам внутри класса. это функция, которая принимает прототип класса и ключ свойства в качестве входных параметров. В приведенном ниже, например. мы можем получить доступ к значениям статических свойств, но не к значению свойства экземпляра, поскольку декораторы создаются до создания экземпляра.
function propetryDecorators(target:any,propertyKey:string) { console.log(target.constructor.name); console.log(`property Key name :${propertyKey}`); /*Property value is undefined for non staic property as it is not yet initialized, but we can access the value of static property here. */ console.log(`property value :${target[propertyKey]}`); } export class propetryDecoratorExample { @propetryDecorators name:string = "property inside class" @propetryDecorators static staticProperty:string ="Static property"; } let instance = new propetryDecoratorExample();
Декораторы методов:
Как следует из названия, эти декораторы применяются к методу в классе. Декораторы методов — это функции с тремя параметрами (прототип класса, имя метода и необязательный дескриптор параметра о методе). например AuthGaurd() в Nest является примером декоратора метода. AuthGaurd срабатывает перед вызовом метода.
Декораторы параметров
Украсить параметры метода. Например, @Body(), @Param() в маршрутах Nest js имеют тип декоратора параметров. Декораторы параметров можно использовать для проверки того, является ли параметр частью метода. Для дальнейшего исследования параметра скажите тип параметра, нам нужно установить сторонний инструмент npm install Reflect-Metadata — save-dev и включить emitDecoratorMetadata: true в файле tsconfig.json.
import 'reflect-metadata'; function paramDecorator(target:any,methodName:string, parameterIndex:number) { console.log(`target: ${target.constructor.name}`); console.log(`methodName : ${methodName}`); console.log(`parameterIndex : ${parameterIndex}`); //using reflection to probe more on the parameter. let designType = Reflect.getMetadata( "design:type", target, methodName); console.log(`designType: ${designType}`); let designParamTypes = Reflect.getMetadata( "design:paramtypes", target, methodName); console.log(`paramtypes : ${designParamTypes}`); if(designParamTypes !== String) { console.log("not string"); } } class ClassType { Method(@paramDecorator param:number , nonParameterDecorator:string) {} } After enabling the “emitDecoratorMetadata”: true, Generated .js file will have info about the __decorate __metadata. __decorate([ __param(0, paramDecorator), __metadata("design:type", Function), __metadata("design:paramtypes", [Number, String]), __metadata("design:returntype", void 0) ], ClassType.prototype, "Method", null);
Ссылки для дальнейшего чтения по этой теме
Сценарий Packt Mastering Type, второе издание, г-н Натан Розенталс
https://docs.nestjs.com/custom-decorators
https://javascript.plainenglish.io/master-the-typescript-keyof-type-operator-bf7f18865a8b
Спасибо за чтение. До новых встреч Желаю вам всего наилучшего :)