Typescript的装饰器
装饰器的定义
- 装饰器
- 就是一个函数
- 可以注入到:类、方法、属性、参数、对象
- 扩展其功能
- 装饰器要解决的问题
- 装饰器就是解决在不修改类、属性、方法、参数的时候为其添加额外的功能。
- 高阶组件本质上也采用了装饰器的思想
- 在
Nets.js
中装饰器可以解决依赖注入的问题 - 有了依赖注入,能大大降低项目的耦合度,大大提升项目的扩展性
- 在
- 依赖注入核心思想
- 使用和创建分离
装饰器的分类
- 类装饰器
- 属性装饰器
- 方法装饰器
- 参数装饰器
- 元数据的装饰器
装饰器的两种写法
- 使用时不传参
- 装饰器工厂:使用时可以传参
环境搭建
安装
ts-node
- 可以使用ts-node
命令直接运行*.ts
文件,不需要先编译成*.js
再使用node
执行安装
concurrently
,支持合并执行,同时运行多个script
命令新建目录,初始化TS配置,生成
tsconfig.json
生成Node包管理文件
pakcage.json
shell npm init
配置文件修改配置支持,修改
tsconfig.json
- 解开装饰器配置- 支持普通装饰器
- 支持元数据装饰器
- 设置源码目录和编译生成JS代码目录
配置
package.json
- 监控dist/teaching
目录中的js
文件,变化时执行node
命令 - 合并启动 - 命令解决typescript
编译装饰器类时出现的bugtsconfig.json
中配置装饰器配置这是避免代码报错- 编译执行需要在指定支持装饰器选项
ts-node
命令配置- 这个配置需要根据文件名进行修改,后面会有提示
"dev:build": "tsc -w", "dev:start": "nodemon --watch dist/decorators js --exec node ./dist/decorators/1ClassDecorator.js", "start": "concurrently npm:dev:*", "tsc": "tsc src/decorators/1ClassDecorator.ts -- target ES5 -w --experimentaDecorators", "ctrl": "ts-node src/controller/HomeController.ts", "beginapp": "nodemon --watch src/ -e ts --exec ts-node ./src/expressapp.ts"
创建
src/decorators
类装饰器
- 不带参数的类装饰器
代码
function FirstClassDecorator(targetClass: any) { let targetClassObj = new targetClass() targetClassObj.buy() // 下单购买 console.log("targetClass.name: ", targetClass.name) // targetClass.name: CustomerService } @FirstClassDecorator class CustomerService { name: string = "下单" constructor() {} buy() { console.log(this.name + "购买") } placeOrder() { console.log(this.name + "下单购买") } } export {}
package.json
配置- 当前代码的文件名
1ClassDecorator.ts
- 修改
1ClassDecorator.js
为1ClassDecorator.js
{ "name": "ts-examples", "version": "1.0.0", "description": "", "scripts": { "dev:build": "tsc -w", "dev:start": "nodemon --watch dist/decorators js --exec node ./dist/decorators/1ClassDecorator.js", "start": "concurrently npm:dev:*", "tsc": "tsc src/decorators/1ClassDecorator.ts -- target ES5 -w --experimentaDecorators", "ctrl": "ts-node src/controller/HomeController.ts", "beginapp": "nodemon --watch src/ -e ts --exec ts-node ./src/expressapp.ts" }, "author": "", "license": "ISC", "dependencies": { "concurrently": "^8.2.2", "nodemon": "^3.0.1" } }
- 当前代码的文件名
运行代码
JS源码
"use strict"; // 1. 底层JS **组合装饰器和目标类** __decorate函数 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { // argsnum 参数个数 var argsnum = arguments.length; // targetinfo 被装饰器修饰的目标【本案例为类】 // argsnum=2 装饰器修饰的是类或者构造器参数,targetinfo=target[类名] // argsnum=4 装饰器修饰的是方法【第四个参数desc等于null] targetinfo=该方法的数据属性【desc = Object.getOwnPropertyDescriptor(target, key) 】 // argsnum=3 装饰器修饰的是方法参数或者属性,targetinfo=undefined var targetinfo = argsnum < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc; console.log("target: ", target) // target : [Function: CustomerService] console.log("targetinfo: ", targetinfo) // targetinfo: [Function: CustomerService] // 由于无参数,argsnum < 3, 其实是torgetinfo = target // decorators: 保存``装饰器数组``元素 // decorators = [FirstClassDecorator] var decorator; // 元数据信息,支持reflect-metadata元数据 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") { targetinfo = Reflect.decorate(decorators, target, key, desc); } else // 装饰器循环,倒着循环,说明同一个目标上有多个装饰器,执行顺序是倒着执行 for (var i = decorators.length - 1; i >= 0; i--) { if (decorator = decorators[i]) { // 如果参数小于3【decorator为类装饰器或者构造器参数装饰器】执行decorator(targetinfo)直接执行decorator装饰器,并传递目标targetinfo,这里是类 // 如果参数大于3【decorator为方法装饰器】 直接执行 decorator(target, key, targetinfo) // 如果参数等于3 【decorator为方法参数装饰器或者属性装饰器】 直接执行decorator(target, key) // targetinfo最终为各个装饰器执行后的返回值,但如果没有返回值,直接返回第S100行的targetinfo // 这里返回一个新的targetinfo // 是把原来的targetinfo 传入到每一个装饰器函数中 // 将CustomerService 传入到装饰器函数中,将执行逻辑交给装饰器内部执行 // 如果函数有返回值 // - 那么targetinfo就为装饰器的返回值 // - 如果装饰器函数无返回值,则执行`|| targetinfo` targetinfo = (argsnum < 3 ? decorator(targetinfo) : argsnum > 3 ? decorator(target, key, targetinfo) : decorator(target, key)) || targetinfo; console.log("targetinforesult:", targetinfo) } } // 参数数目小于三个argsnum < 3, 直接返回targetinfo return argsnum > 3 && targetinfo && Object.defineProperty(target, key, targetinfo), targetinfo; } // 底层JS 组合装饰器和目标类 __decorate函数结束 // 不带参数的装饰器 function FirstClassDecorator(targetClass) { var targetClassObj = new targetClass(); targetClassObj.buy(); // 下单购买 console.log("targetClass.name: ", targetClass.name); // targetClass.name: CustomerService } // 被装饰的类 var CustomerService = /** @class */ (function () { function CustomerService() { this.name = "下单"; } CustomerService.prototype.buy = function () { console.log(this.name + "购买"); }; CustomerService.prototype.placeOrder = function () { console.log(this.name + "下单购买"); }; // 调用`__decorate`函数 // - 参数 // - 装饰器列表 // - 类构造函数名称 CustomerService CustomerService = __decorate([ FirstClassDecorator, __metadata("design:paramtypes", []) ], CustomerService); return CustomerService; }())
- 带参数的类装饰器
代码
function FirstClassDecorator(params: any) { console.log("params out: ", params) return function(targetClass: any) { let targetClassObj = new targetClass() targetClassObj.buy() console.log("targetClass.name: ", targetClass.name) console.log("params in: ", params) } } @FirstClassDecorator("我是用来修饰CustomService类的装饰器参数") class CustomerService { name: string = "下单" constructor() {} buy() { console.log(this.name + "购买") } placeOrder() { console.log(this.name + "下单购买") } } export {}
package.json
配置- 当前代码的文件名
2ClassDecorator.ts
- 修改
1ClassDecorator.js
为2ClassDecorator.js
{ "name": "ts-examples", "version": "1.0.0", "description": "", "scripts": { "dev:build": "tsc -w", "dev:start": "nodemon --watch dist/decorators js --exec node ./dist/decorators/2ClassDecorator.js", "start": "concurrently npm:dev:*", "tsc": "tsc src/decorators/1ClassDecorator.ts -- target ES5 -w --experimentaDecorators", "ctrl": "ts-node src/controller/HomeController.ts", "beginapp": "nodemon --watch src/ -e ts --exec ts-node ./src/expressapp.ts" }, "author": "", "license": "ISC", "dependencies": { "concurrently": "^8.2.2", "nodemon": "^3.0.1" } }
- 当前代码的文件名
运行代码
JS源码
"use strict"; // 1. 底层JS **组合装饰器和目标类** __decorate函数 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { // argsnum 参数个数 var argsnum = arguments.length; // targetinfo 被装饰器修饰的目标【本案例为类】 // argsnum=2 装饰器修饰的是类或者构造器参数,targetinfo=target[类名] // argsnum=4 装饰器修饰的是方法【第四个参数desc等于null] targetinfo=该方法的数据属性【desc = Object.getOwnPropertyDescriptor(target, key) 】 // argsnum=3 装饰器修饰的是方法参数或者属性,targetinfo=undefined var targetinfo = argsnum < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc;//S100 console.log("target : ", target) // [Function: CustomerService] console.log("targetinfo: ", targetinfo) // [Function: CustomerService] // argsnum < 3 targetinfo = target // decorators: 保存``装饰器的数组``元素 // decorators = [FirstClassDecorator] var decorator; // 元数据信息,支持reflect-metadata元数据 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") { targetinfo = Reflect.decorate(decorators, target, key, desc); } else // 装饰器循环,倒着循环,说明同一个目标上有多个装饰器,执行顺序是倒着执行 for (var i = decorators.length - 1; i >= 0; i--) { if (decorator = decorators[i]) { // 如果参数小于3【decorator为类装饰器或者构造器参数装饰器】执行decorator(targetinfo)直接执行decorator装饰器,并传递目标targetinfo,这里是类 // 如果参数大于3【decorator为方法装饰器】 直接执行 decorator(target, key, targetinfo) // 如果参数等于3 【decorator为方法参数装饰器或者属性装饰器】 直接执行decorator(target, key) // targetinfo最终为各个装饰器执行后的返回值,但如果没有返回值,直接返回第S100行的targetinfo targetinfo = (argsnum < 3 ? decorator(targetinfo) : argsnum > 3 ? decorator(target, key, targetinfo) : decorator(target, key)) || targetinfo; console.log("Final targetinfo result:", targetinfo) } } return argsnum > 3 && targetinfo && Object.defineProperty(target, key, targetinfo), targetinfo; } // 带参数的装饰器 function FirstClassDecorator(params: any) { console.log("params out: ", params) return function(targetClass: any) { let targetClassObj = new targetClass() targetClassObj.buy() console.log("targetClass.name: ", targetClass.name) console.log("params in: ", params) } } // 被装饰的类 var CustomerService = /** @class */ (function () { function CustomerService() { this.name = "下单"; } CustomerService.prototype.buy = function () { console.log(this.name + "购买"); }; CustomerService.prototype.placeOrder = function () { console.log(this.name + "下单购买"); }; // 调用 // - 参数 // - 装饰器列表 // - 类构造函数名称 CustomerService // 和不带参数的区别就是 // - 会把带参数装饰器先执行一遍 // - 带参数的装饰器,返回的是一个函数作为装饰器函数 // - 然后传入被装饰的类 CustomerService = __decorate([ FirstClassDecorator("我是用来修饰CustomService类的装饰器参数"), ], CustomerService); return CustomerService; }());
泛型工厂继承装饰器
- 毫无相干的两个类可以相互赋值
- 条件是:属性相同
- 必须拥有我的所有属性(可以多,不能少),才能赋值给我
- 等号右边完全包含左边属性
- 父类类名,可以接受子类的类名(多态)
- 泛型工厂继承装饰器
装饰器类作为子类,继承父类的属性和方法
返回装饰器子类的类名
完成类的功能扩展和替换
代码
// 1. 完成日志信息的装饰器 function LoggerInfoDecorator<T extends { new(...args: any): any}>(targetClass: T) { class LoggerInfoDecorator extends targetClass { constructor(...args: any) { super(...args) console.log("Logging INFO targetClass: ", (targetClass as any).name) } } return LoggerInfoDecorator } // 2. 目标类 @LoggerInfoDecorator class Test { name!: string age!: number // 1. 先执行原来的构造函数 constructor(name: string) { this.name = name } eat() { console.log(this.name, "Eating Food") } } let test = new Test("Zhangsan") test.eat() export {}
JS源码
// 1. 继承源码代码 let __extends = (function (Son, Parent) { function getStaticExtendsWithForIn (Son, Parent) { for (let key in Parent) { if (Object.prototype.hasOwnProperty.call(Parent, key)) { Son[key] = Parent[key] } } } function getStaticExtendsWithObjectkeys (Son, Parent) { Object.keys(Parent).forEach((key) => { Son[key] = Parent[key] }) } function getStaticExtendsWithProto (Son, Parent) { Son.__proto__ = Parent; } let MyextendStatics = function (Son, Parent) { let MyextendStatics = Object.setPrototypeOf || getStaticExtendsWithForIn || getStaticExtendsWithObjectkeys || getStaticExtendsWithProto return MyextendStatics(Son, Parent) } return function (Son, Parent) { MyextendStatics(Son, Parent) function Middle () { this.constructor = Son; } if (Parent) {//如果不为空 如果父类存在 Middle.prototype = Parent.prototype; Son.prototype = new Middle() } else {// 如果父类不存在 Son.prototype = Object.create(null) } console.log("Object.create(null):", Object.create(null)); } }()) // 2. 底层JS 组合装饰器和目标类 __decorate 函数 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { // argsnum 参数个数 var argsnum = arguments.length; // targetinfo 被装饰器修饰的目标【类或属性或方法或方法参数,本案例为类】 // argsnum=2 装饰器修饰的是类或者构造器参数,targetinfo=target[类名] // argsnum=4 装饰器修饰的是方法【第四个参数desc等于null] targetinfo=该方法的数据属性【desc = Object.getOwnPropertyDescriptor(target, key) 】 // argsnum=3 装饰器修饰的是方法参数或者属性,targetinfo=undefined var targetinfo = argsnum < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc;//S100 // decorator保存装饰器数组元素 var decorator; // 元数据信息,支持reflect-metadata元数据 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") { targetinfo = Reflect.decorate(decorators, target, key, desc); } else // 装饰器循环,倒着循环,说明同一个目标上有多个装饰器,执行顺序是倒着执行 for (var i = decorators.length - 1; i >= 0; i--) { if (decorator = decorators[i]) { // 如果参数小于3【decorator为类装饰器或者构造器参数装饰器】执行decorator(targetinfo)直接执行decorator装饰器,并传递目标targetinfo,这里是类 // 如果参数大于3【decorator为方法装饰器】 直接执行 decorator(target, key, targetinfo) // 如果参数等于3 【decorator为方法参数装饰器或者属性装饰器】 直接执行decorator(target, key) // targetinfo最终为各个装饰器执行后的返回值,但如果没有返回值,直接返回第S100行的targetinfo targetinfo = (argsnum < 3 ? decorator(targetinfo) : argsnum > 3 ? decorator(target, key, targetinfo) : decorator(target, key)) || targetinfo; console.log("targetinforesult:", targetinfo) } } return argsnum > 3 && targetinfo && Object.defineProperty(target, key, targetinfo), targetinfo; } // 底层 JS 组合装饰器和目标类 __decorate 函数结束 // 2.装饰器类 function LoggerInfoDecorator(targetClass) { var LoggerInfoDecorator = /** @class */ (function (_super) { __extends(LoggerInfoDecorator, _super); // ****继承关系**** function LoggerInfoDecorator() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var _this = _super.apply(this, args) || this; console.log("Logging INFO targetClass: ", targetClass.name); return _this; } return LoggerInfoDecorator; }(targetClass)); return LoggerInfoDecorator; } // 2. 目标类 var Test = /** @class */ (function () { // 1. 先执行原来的构造函数 function Test(name) { this.name = name; } Test.prototype.eat = function () { console.log(this.name, "Eating Food"); }; Test = __decorate([ LoggerInfoDecorator, ], Test); return Test; }()); // 4.测试 var test = new Test("ok");
方法装饰器
包含以下内容
- 方法装饰器的实现
- 方法装饰器拦截器意义
- 拦截器的前置、后置功能实现
不带参数方法装饰器实现
代码
/* @param targetClassPrototype 类名 @param methodname : value 方法名 @param methodDecri: PropertyDescriptor 数据属性 PropertyDescriptor的定义 - 用来控制当前方法的属性 interface PropertyDescriptor { configurable?: boolean // 是否可配置 enumerable?: boolean // 是否可枚举 value?: any // 方法名 writable?: boolean // 是否可写 get?(): any // get属性 set?(v: any): void // set属性 } */ function MyMethodDecorator(targetClassPrototype: any, methodname: string, methodDecri: PropertyDescriptor) { console.log("targetClassPropertotype: ", targetClassPrototype) console.log("key: ", methodname) console.log("Data Attr: ", methodDecri) methodDecri.value() // 当前被装饰的函数,数据属性中的value属性,这里就是执行被修饰的函数 } // 目标类 class RoleService { roleName: string = "Admin" constructor () {} @MyMethodDecorator DistribRoles() { console.log("Generating Role ...") } }
带参数方法装饰器实现
代码
/* @param targetClassPrototype 类名 @param methodname : value 方法名 @param methodDecri: PropertyDescriptor 数据属性, value 表示的是方法体 PropertyDescriptor的定义 - 用来控制当前方法的属性 interface PropertyDescriptor { configurable?: boolean // 是否可配置 enumerable?: boolean // 是否可枚举 value?: any // 方法名 writable?: boolean // 是否可写 get?(): any // get属性 set?(v: any): void // set属性 } */ function MyMethodDecorator(params: any) { return function (targetClassPrototype: any, methodname: string, methodDecri: PropertyDescriptor) { console.log("targetClassPropertotype: ", targetClassPrototype) console.log("key: ", methodname) console.log("Data Attr: ", methodDecri) console.log("Params: ", params) methodDecri.value() // 当前被装饰的函数,数据属性中的value属性,这里就是执行被修饰的函数 } } // 目标类 class RoleService { roleName: string = "Admin" constructor () {} @MyMethodDecorator("/Service") DistribRoles() { console.log("Generating Role ...") } }
方法拦截器的意义
- 改良原有的函数,可以添加前置和后置的处理代码
属性装饰器
- 装饰器参数
- targetClassPrototype: object
- 类名
- attrname: string | symbol
- 属性名
- targetClassPrototype: object
- 属性装饰器的应用场景
- 在属性声明时
- 进行拦截
- 添加逻辑
- 存储相关的元数据
- 在属性声明时
- 属性装饰器应用: 元数据注入
- 可以使用属性装饰器为属性附加额外的元数据
在某些框架中非常有用,比如Angular的
@Input()
用于定义一个类的属性为输入属性
- 可以使用属性装饰器为属性附加额外的元数据
- 属性装饰器应用:验证
- 通过属性装饰器来验证类的属性值
可以定义一个
@IsPositive
装饰器,确保属性值是正数function IsPositive(target: any, key: string) { const storedValue = this[key] Object.defineProperty(target, key, { get: function() { return storedValue }, set: function(value) { if (value <= 0) { throw new Error("Value should be a positive number") } storedValue = value } }) } class MyClass { @IsPositive positiveNumber: number }
- 属性装饰器应用:日志与审计
每次属性值更改时记录日志
function LogChanges(target: any, key: string) { let storedValue = this[key] Object.defineProperty(target, key, { get: function() { return storedValue }, set function(value) { console.log(`Property ${key} changed from ${storedValue}` to ${value}) } }) } class MyClass { @LogChanges myProperty: string }
- 属性装饰器的其他应用场景
- 延迟加载/懒加载
- 当访问某个属性时,如果数据还没有被加载,则从后端或其他数据源动态加载
- 自动绑定
- 在React中自动绑定方法到当前实例,以便在回调或事件处理程序中使用正确的
this
- 在React中自动绑定方法到当前实例,以便在回调或事件处理程序中使用正确的
- 存储映射关系
- 在ORM框架中,属性装饰器可以用来定义属性与数据库列之间的映射关系
- 计算属性的缓存
- 对于计算成本高的属性,可以使用装饰器来缓存它的值,只在需要时计算
- 延迟加载/懒加载
- 通过属性装饰器来验证类的属性值
参数装饰器
- 含义
- 应用于类构造函数或方法参数的
- 它们在运行时可以接触到所属的类、方法和参数索引等信息
- 参数装饰器的应用场景
- 依赖注入
- 当类的实例被创建时,所需的依赖会自动被注入到构造函数参数中
- 元数据标记
- 在某些场景下,你可能想为某个参数标记元数据,之后这些元数据可以用于验证、转换或其他目的
- 日志和审计
- 可以用来记录或审计方法调用和参数值,特别是对于某些关键参数
- 转换或序列化
- 在方法调用之前,参数装饰器可以用来转换或序列化参数值
- 参数校验
- 参数装饰器可以与反射元数据结合使用,对方法参数进行类型校验
- 访问控制和授权
- 在某些场景下,可以使用参数装饰器检查用户权限,决定是否允许对某个方法进行访问或操作
- 关联路由和请求数据
- 在NestJS,参数装饰器可以用来提取路由参数、查询参数、请求体或请求头
- 依赖注入
访问器装饰器
- 定义
- 用于拦截类的访问器(
get
和set
)
- 用于拦截类的访问器(
- 访问器装饰器的应用场景
- 值的验证
在为属性赋值时(通过setter)对其进行验证
function Validate(target: any, key: string, descriptor: PropertyDescriptor) { const originSet = descriptor.set descriptor.set = function (value: any) { if (!value) { throw new Error('Invalid value') } originSet?.call(this, value) } } class MyClass { private _name: string @Validate set name(value: string) { this._name = value } }
日志
在获取或设置属性值时进行日志记录
function Log(target: any, key: string, descriptor: PropertyDescriptor) { const originalGet = descriptor.get const originalSet = descriptor.set if (originalGet) { descriptor.get = function () { console.log(`Getting ${key}`) return originalGet.call(this) } } if (originalSet) { descriptor.set = function (value: any) { console.log(`Setting ${key} to ${value}`) originalSet.call(this, value) } } } class MyClass { private _value: number @Log get value(): number { return this._value } set value(v: number) { this._value = v } }
延迟初始化/懒加载
- 在第一次访问属性时初始化它
计算属性的缓存
- 对于计算代价高昂的属性,可以使用访问器装饰器来缓存其值
自动通知
- 当属性值改变时,自动触发某些动作或事件
数据绑定和观察者模式
- 当属性值更改时,通知关联的UI或其他依赖项
- 值的验证
元数据装饰器
- 元数据
- 为了帮助类、方法、属性实现一定的功能,而附加在其上的一些数据
- 分类
- 自定义元数据
- 内置元数据(reflect-metadata自带)
- 初步理解
- 在定义类或类方法或对象的时候,可以设置一些元数据,我们可以获取到在类与类方法上添加元数据
- 需要引入第三方库
reflect-metadata
- 采用
@Reflect.metadata
来实现 - 元数据是指描述东西时用的数据
装饰器执行顺序
- 执行顺序
- 属性装饰器
- 方法参数装饰器
- 方法装饰器
- 类装饰器
- 装饰器的使用方式
- 前面顺序的装饰器可以保存数据
- 后面顺序的装饰器可以获取数据
装饰器总结
- 属性装饰器(Property Decorators)
- 应用于属性声明
- 不可以修改属性的描述
- 但可以使用它来存储关于属性的元数据
- 属性装饰器的表达式将在运行时作为函数调用,并带有以下两个参数
- 静态成员的类构造函数,或实例成员的类原型
- 成员名称
- 应用于属性声明
- 参数装饰器(Parameter Decorators)
- 应用于类构造函数或方法的参数
- 参数装饰器在运行时可以获取关于参数的信息
- 参数装饰器的表达式将在运行时作为函数调用,并带有以下三个参数
- 静态成员的类构造函数,或实例成员的类原型(the prototype of the class for an instance member)
- 成员名称(the name of member)
- 参数在函数参数列表(function parameter list)中的序号索引(index of the parameter)
- 方法装饰器(Method Decorators)
- 应用于方法的属性描述符
- 可用于观察、修改或替换方法定义
- 类装饰器(Class Decorators)
- 应用于类的构造函数
- 可以用来监视、修改或替换类的定义
- 访问器装饰器(Parameter Decorators)
- 应用于对象的访问器的属性描述符
- 不能同时使用在一个成员的
get
和set
访问器,只能应用于其中之一
- 案例代码
代码
function ClassDecorator() { console.log('ClassDecorator: evaluated'); return function (target) { console.log('ClassDecorator: called'); } } function PropertyDecorator() { console.log('PropertyDecorator: evaluated'); return function (target, propertyKey) { console.log('PropertyDecorator: called'); } } function MethodDecorator() { console.log('MethodDecorator: evaluated'); return function (target, propertyKey, descriptor) { console.log('MethodDecorator: called'); } } function ParameterDecorator() { console.log('ParameterDecorator: evaluated'); return function (target, propertyKey, parameterIndex) { console.log('ParameterDecorator: called'); } } @ClassDecorator() class MyClass { @PropertyDecorator() myProperty: string; myMethod(@ParameterDecorator() param: string) { @MethodDecorator() } }
执行结果