全国协议5人面授小班,企业级独立开发考核,转业者的IT软件工程师基地 登录/注册 | 如何报名
当前位置: 前端开发   >  TypeScript Reflect Metadata
admin · 更新于 2021-08-06

1. 解释

Reflect,翻译为『反射』,Metadata,翻译为『元数据』。反射这个概念在 Java 等众多语言中已经广泛运用,Reflect Metadata 就是通过装饰器来给类添加一些自定义的信息,然后通过反射将这些信息提取出来,也可以通过反射来添加这些信息。

2. 安装使用

通过 npm 安装这个库:

npm i reflect-metadata --save
代码块
  • 1

而且需要在 tsconfig.json 中配置:

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }}
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

命令行使用:

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata
代码块
  • 1

当启用后,只要 reflect-metadata 库被引入了,设计阶段添加的类型信息可以在运行时使用。

import 'reflect-metadata'@Reflect.metadata('token', 'aW1vb2M=')class Employee {

  @Reflect.metadata('level', 'D2')
  salary() {
    console.log('这是个秘密')
  }

  @Reflect.metadata('times', 'daily')
  static meeting() {}}const token = Reflect.getMetadata('token', Employee)const level = Reflect.getMetadata('level', new Employee(), 'salary')const times = Reflect.getMetadata('times', Employee, 'meeting')console.log(token) // aW1vb2M=console.log(level) // D2console.log(times) // daily
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

TIPS: 注意, 实例方法与静态方法取元数据是不同的,实例方法需要在类的实例上取元数据,静态方法直接在类上取元数据。

3. API

import 'reflect-metadata'
 // 元数据的命令式定义,定义对象或属性的元数据Reflect.defineMetadata(metadataKey, metadataValue, target)Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
 // 检查对象或属性的原型链上是否存在元数据键let result = Reflect.hasMetadata(metadataKey, target)let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 // 检查对象或属性是否存在自己的元数据键let result = Reflect.hasMetadata(metadataKey, target)let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 // 获取对象或属性原型链上元数据键的元数据值let result = Reflect.getMetadata(metadataKey, target)let result = Reflect.getMetadata(metadataKey, target, propertyKey)
 // 获取对象或属性的自己的元数据键的元数据值let result = Reflect.getOwnMetadata(metadataKey, target)let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey)
 // 获取对象或属性原型链上的所有元数据键let result = Reflect.getMetadataKeys(target)let result = Reflect.getMetadataKeys(target, propertyKey)
 // 获取对象或属性的所有自己的元数据键let result = Reflect.getOwnMetadataKeys(target)let result = Reflect.getOwnMetadataKeys(target, propertyKey)
 // 从对象或属性中删除元数据let result = Reflect.deleteMetadata(metadataKey, target)let result = Reflect.deleteMetadata(metadataKey, target, propertyKey)
 // 通过装饰器将元数据应用于构造函数@Reflect.metadata(metadataKey, metadataValue)class C {
  // 通过装饰器将元数据应用于方法(属性)
  @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }}
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

4. 结合装饰器使用

Reflect Metadata 结合上节介绍的装饰器:

import 'reflect-metadata'function get(path: string): MethodDecorator {
  return (target, name) => {
    Reflect.defineMetadata('path', path, target, name)
  }}class Employee {
  @get('/init')
  async init() {}}const metadata = Reflect.getMetadata('path', new Employee(), 'init')console.log(metadata) // '/init'
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

解释: 如果经常开发 Node.js 的同学对这样的写法是不是有些熟悉呢?类方法 init() 上的装饰器 get() 传入元数据 '/init',再通过反射拿到这个路由信息,将这些路由信息进行一定的封装,然后绑定在 koa-router 上,就能达到自动加载路由的功能。

5. 小结

本节介绍了 Reflect Metadata 的一些基础使用方式,一些基础库源码如 vue-class-componentAngular 均使用了 Reflect Metadata ,有兴趣的可以深入源码学习下。


为什么选择汉码未来