TS 装饰器(2): 元数据

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容