TS 装饰器(2): 元数据

2022-02-27  本文已影响0人  菜鸡前端

TS 装饰器(2): 元数据

装饰器函数中 ,我们可以拿到类、方法、访问符、属性、参数的基本信息,如它们的名称,描述符等。获取更多信息就需要通过另外的方式来进行:元数据

1、什么是元数据?

元数据:用来描述数据的数据,在我们的程序中,对象、类等都是数据,它们描述了某种数据。另外还有一种数据,它可以用来描述 对象、类,这些用来描述数据的数据就是元数据

在编译过程中产生的元数据是非常重要的信息,比如在 nestjs 框架中 DI 和 IOC 的实现久依赖了他们。

2、reflect-metadata

首先,需要安装 reflect-metadata

2.1、定义元数据

我们可以给类、方法 等数据定义元数据,元数据会被附加到指定的 类、方法等数据之上,但是又不会影响类、方法本身的代码。

2.2、使用语法

(1) 设置
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)

(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、装饰器简化操作

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 会在编译之后自动给类、方法、访问符、属性、参数添加如下几个元数据:

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
上一篇 下一篇

猜你喜欢

热点阅读