TS 装饰器(2): 元数据
在装饰器
函数中 ,我们可以拿到类、方法、访问符、属性、参数的基本信息,如它们的名称,描述符等。获取更多信息就需要通过另外的方式来进行:元数据
。
1、什么是元数据?
元数据:用来描述数据的数据,在我们的程序中,对象、类等都是数据,它们描述了某种数据。另外还有一种数据,它可以用来描述 对象、类,这些用来描述数据的数据就是元数据。
在编译过程中产生的元数据是非常重要的信息,比如在 nestjs 框架中 DI 和 IOC 的实现久依赖了他们。
2、reflect-metadata
首先,需要安装 reflect-metadata
。
2.1、定义元数据
我们可以给类、方法 等数据定义元数据,元数据会被附加到指定的 类、方法等数据之上,但是又不会影响类、方法本身的代码。
2.2、使用语法
(1) 设置
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
- metadataKey:meta 数据的 key
- metadataValue:meta 数据的 值
- target:meta 数据附加的目标
- propertyKey(可选):对应的 property key
(2) 获取
Reflect.getMetadata(metadataKey, target, propertyKey)
import "reflect-metadata";
class A {
public static method1() {}
public method2() {}
}
let obj = new A();
Reflect.defineMetadata("key", 1, A);
Reflect.defineMetadata("key", 2, A, "method1");
Reflect.defineMetadata("key", 3, obj);
Reflect.defineMetadata("key", 4, A, "method2");
console.log(Reflect.getMetadata("key", A));
console.log(Reflect.getMetadata("key", A, "method1"));
console.log(Reflect.getMetadata("key", obj));
console.log(Reflect.getMetadata("key", obj, "method2"));
2.3、装饰器简化操作
- 通过
Reflect.defineMetadata
方法调用来添加元数据 - 通过
@Reflect.metadata
装饰器来添加元数据
import "reflect-metadata";
@Reflect.metadata("key", 1)
class A {
@Reflect.metadata("key", 2)
public static method1() {}
@Reflect.metadata("key", 4)
public method2() {}
}
let obj = new A();
console.log(Reflect.getMetadata("key", A));
console.log(Reflect.getMetadata("key", A, "method1"));
console.log(Reflect.getMetadata("key", obj));
console.log(Reflect.getMetadata("key", obj, "method2"));
3、使用 emitDecoratorMetadata
如何知道一个方法中有多少个参数,每个参数的类型是什么呢?tsconfig.json 中有一个配置 emitDecoratorMetadata,开启该特性,typescript 会在编译之后自动给类、方法、访问符、属性、参数添加如下几个元数据:
-
design:type
:被装饰目标的类型- 装饰器作用于成员属性:属性的标注类型
- 装饰器作用于成员方法:Function 类型
-
design:paramtypes
: 被装饰目标的参数类型- 装饰器作用于成员方法:方法形参列表的标注类型
- 装饰器作用于类:构造函数形参列表的标注类型
-
design:returntype
- 成员方法:函数返回值的标注类型
3.1、方法装饰器实验
源码:
function f() {
return function (target: any, name: string, descriptor: PropertyDescriptor) {
console.log(descriptor.value.length);
};
}
class B {
name: string;
constructor(a: string) {
this.name = a;
}
@f()
method(a: string, b: string): string {
return "a";
}
}
产物:
// 太长了,隐藏实现
var __decorate = function () {}
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
function f() {
return function (target, name, descriptor) {
console.log(descriptor.value.length);
};
}
var B = /** @class */ (function () {
function B(a) {
this.name = a;
}
B.prototype.method = function (a, b) {
return "a";
};
__decorate([
f(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", String)
], B.prototype, "method", null);
return B;
}());
3.2、类装饰器实验
@testable
class MyTestableClass {
constructor (name: string, age: number) {}
}
function testable(target: Function) {
(target as any).isTestable = true;
}
(MyTestableClass as any).isTestable // true
产物:
var MyTestableClass = /** @class */ (function () {
function MyTestableClass(name, age) {
}
MyTestableClass = __decorate([
testable,
__metadata("design:paramtypes", [String, Number])
], MyTestableClass);
return MyTestableClass;
}());
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable; // true
网友评论