reflect-metadata 是ES7 的提案 ,TypeScript 1.5 已经开始使用。reflect-metadata是一个单独的npm 包,具体介绍可以看看官方介绍。

系列教程

  • TypeScript系列教程一《开篇》
  • TypeScript系列教程二《安装起步》
  • TypeScript系列教程三《基础类型》
  • TypeScript系列教程四《扩展类型》
  • TypeScript系列教程五《对象类型》》
  • TypeScript系列教程六《泛型》
  • TypeScript系列教程七《接口》
  • TypeScript系列教程八《类》
  • TypeScript系列教程九《高级类型》
  • TypeScript系列教程九《类型转换》-- keyof和typeof 操作
  • TypeScript系列教程九《类型转换》-- 索引访问类型
  • TypeScript系列教程九《类型转换》-- 条件类型
  • TypeScript系列教程九《类型转换》-- 映射类型
  • TypeScript系列教程九《类型转换》-- 条件类型
  • TypeScript系列教程九《类型转换》-- 模板文本类型
  • TypeScript系列教程十《模块》
  • TypeScript系列教程十一《装饰器》 – 装饰器与继承
  • TypeScript系列教程十一《装饰器》 – 类装饰器
  • TypeScript系列教程十一《装饰器》 – 方法装饰器
  • TypeScript系列教程十一《装饰器》 – reflect-metadata
  • TypeScript系列教程十一《装饰器》 – 属性装饰器
  • TypeScript系列教程十一《装饰器》 – 参数装饰器

reflect-metadata 拆成两个单词,reflect 反射和 metadata,通俗理解 利用反射的原理修改元数据。

元数据就是配置数据的数据,reflect-metadata 利用反射的原理通过key、value的形式给对象、对象属性设置数据,从而不改变其数据结构。

安装配置

首先我们需要单独引入这个包:

npm install reflect-metadata

在tsconfig里打开下面属性支持装饰器和元数据:

  /* Enables experimental support for ES7 decorators.*/"experimentalDecorators": true, /* Enables experimental support for emitting type metadata for decorators. */"emitDecoratorMetadata": true,

API

反射元数据可以在对象或者对象属性上添加元数据,提供装饰器在类的原型对象和对象属性上添加元数据。

//在对象或属性上定义源数据
Reflect.defineMetadata(metadataKey, metadataValue, target);
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);// 检查某个源数据的 key 是否存在某个对象或属性上
let result = Reflect.hasMetadata(metadataKey, target);
let result = Reflect.hasMetadata(metadataKey, target, propertyKey);// 检查是否有自带源数据 key 存在某个对象或属性上
let result = Reflect.hasOwnMetadata(metadataKey, target);
let result = Reflect.hasOwnMetadata(metadataKey, target, propertyKey);// 通过 key 在对象或属性的原型链上获取源数据的值
let result = Reflect.getMetadata(metadataKey, target);
let result = Reflect.getMetadata(metadataKey, target, propertyKey);// 通过 自带源数据 key 在对象或属性的原型链上获取源数据的值
let result = Reflect.getOwnMetadata(metadataKey, target);
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey);// 获取对象或属性原型链上的所有源数据
let result = Reflect.getMetadataKeys(target);
let result = Reflect.getMetadataKeys(target, propertyKey);// 获取对象或属性上所有自带的源数据 keys
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() {}
}

我们已经在 tsconfig.json 中开启了 emitDecoratorMetadata 选项,此时,TypeScript 在编译时定义一些 元数据设计键,目前可用的有:

  • 属性类型元数据 design:type :用于获取类属性的类型

  • 参数类型元数据 design:paramtypes:用于获取方法参数的类型

  • 返回类型元数据 design:returntype:用于获取返回值的类型

目前只有这三个设计键可用,但已经足够覆盖大部分常见场景了。

说了那么多概念,那么这个reflect-matedata 有什么用呢?有哪些使用场景?

使用场景

reflect-matedata 光看api很容易明白,使用也简单,主要是思想和使用场景比较抽象,在什么时候可以使用到他呢?下面总结了几个。

参数统一处理

主要是想统一替换实例,拦截然后重新插入。

示例主要演示了,不论接收什么参数,都可以重新拦截修改注入。

  • 方法装饰器
  • 根据 reflect-matedata design:paramtypes 拿到方法参数类型
  • 根据类型实例化修改然后重新注入

代码:

无论我传男生还是女生,我都统一拦截处理修改成了中性。

import "reflect-metadata";class People {sex:string
} class Women implements People{sex: string = '女生'
}class Man implements People{sex: string = '男生'
}function SexDecorate(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor){let PropsTypes = Reflect.getMetadata('design:paramtypes',target,propertyKey)let p =   new  PropsTypes[0]()p.sex = '中性'let orgMethod = descriptor.value descriptor.value = ()=>{orgMethod(p)}
}class Student {@SexDecorategetSex(obj:People){console.log(obj);}}let man = new Man()
let women = new Women()let std = new Student()
std.getSex(man)
std.getSex(women)

打印结果:

控制反转和依赖注入

在Angular 和nestjs 中有大量的注入,这也是我从新学习装饰器的目的,就是看懂nestjs 代码。

说这个之前,先做个试验:

class Tes {constructor(a:string) {}run(name:string){}
}
console.log(Reflect.getMetadata('design:paramtypes', Tes));

我要通过 Reflect.getMetadata 去构造函数参数,这样是取不出来的,必须加上装饰器。

我加一个装饰器就可以取出来了:


const a:()=>ClassDecorator = ()=>{return (target:Function)=>{}
}@a()
class Tes {constructor(a:string) {}run(name:string){}
}console.log(Reflect.getMetadata('design:paramtypes', Tes));

下面看一段简单的注入实现代码:

import "reflect-metadata";
// 构造函数类型,注入的依赖必须是可以按照这个构造函数构造的。
type Constructor<T = any> = new (...args: any[]) => T;
// 注入依赖装饰器,为了能取到元数据参数。
const Injectable = (): ClassDecorator => target => {};class OtherService {a = 1;
}@Injectable()
class TestService {constructor(public readonly otherService: OtherService) {}testMethod() {console.log(this.otherService.a);}
}const Factory = <T>(target: Constructor<T>): T => {// 获取所有注入的服务const providers = Reflect.getMetadata('design:paramtypes', target); // [OtherService]console.log(providers);// 根据构造函数类型实例化const args = providers.map((provider: Constructor) => new provider());//构造服务并将构造依赖示例参数传入return new target(...args);};Factory(TestService).testMethod(); // 1

到此结束,下面关于参数和属性装饰器示例还要用到reflect-metadata。

TypeScript系列教程十一《装饰器》 -- reflect-metadata相关推荐

  1. TypeScript系列教程十一《装饰器》 -- 属性装饰器

    系列教程 TypeScript系列教程一<开篇> TypeScript系列教程二<安装起步> TypeScript系列教程三<基础类型> TypeScript系列教 ...

  2. jquery系列教程1-选择器全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: jquery系列教程1-选择器全解 jquery系列教程2-style样式操作全解 jquery系列教程3-DOM操作全解 jquery系列教程4-事件 ...

  3. TypeScript(八)装饰器

    目录 前言 定义 类装饰器 基本用法 操作方式 操作类的原型 类继承操作 方法装饰器 属性装饰器 存取器装饰器 参数装饰器 基本用法 参数过滤器 元数据函数实现 参数过滤 效果实践 装饰器优先级 相同 ...

  4. TypeScript reflect-metadata 结合方法装饰器实现的一个自定义语法检查的例子

    reflect-metadata 例子: import 'reflect-metadata';function validate(target: Object,key: string,descript ...

  5. 【总结】1277- 重学 TypeScript 系列教程

    非常不错的 TypeScript 学习资料,一起推荐给小伙伴们,值得好好看看哈~ 以下是正文. TypeScript 是一种由微软开发的自由和开源的编程语言.它是 JavaScript 的一个超集,而 ...

  6. Vue中用TypeScript改写JavaScript及装饰器使用

    TypeScrpt相比JavaScript的主要特点 多了属性声明类型,格式:属性名:声明类型 name:string=""; //此时name属性声明类型为string 复制代码 ...

  7. 【Python教程】装饰器的使用及固定模式

    装饰器的使用: 在不想修改函数的调用方式,但是想给函数添加内容的功能的时候使用 为什么使用装饰器: 软件实体应该是可扩展,而不可修改的.也就是说,对扩展是开放的,而对修改是封闭的. 因此,引出了开放封 ...

  8. python基础教程:装饰器的高级应用

    装饰器和装饰器模式 装饰器模式是面向对象的一种设计模式,支持将行为动态增加到已经存在的对象上.当装饰一个对象的时候,就表示独立与其他类实例对象,为该对象扩展了新的功能. python的装饰器不是装饰器 ...

  9. python基础教程:装饰器

    1. 函数 在python中,函数通过 def关键字.函数名和可选的参数列表定义.通过 return关键字返回值.我们举例来说明如何定义和调用一个简单的函数: >>> def foo ...

  10. js系列教程12-浏览器存储全解

    全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...

最新文章

  1. 互联网金融产品需要什么样的产品经理?
  2. oralce 异常处理 exception
  3. 按照前序遍历和中序遍历构建二叉树
  4. C#—Dev XtraTabControl操作总结如动态增加Tab和关闭选项卡方法等
  5. Nmap 源代码学习四 软件简单使用
  6. day02:关于惯性导航工具箱的学习与使用:use of the progen
  7. 使用Spring Task轻松完成定时任务
  8. 从零开始学习前端JAVASCRIPT — 14、闭包与继承
  9. Python面试题之python是一种什么语言及优缺点
  10. 火车头采集器文章伪原创插件工具
  11. java生成点阵图_点阵字库在JAVA中的实现
  12. Halcon union_straight_contours_xld详解
  13. 为什么用conda?
  14. 2021顶墙十大公认品牌排名榜揭晓
  15. APP设计尺寸规范大全,APP界面设计新手教程【官方版】
  16. IDEA 调试技巧,比 Eclipse 强太多了!
  17. 教你如何在云服务器上安装并配置web服务器(这里以nginx服务器为例,操作系统linux)
  18. 1G2G3G4G5G:一部波澜壮阔的移动通信史
  19. jQuery学习笔记(二)使用选择器一
  20. vue后台管理系统实践方案总结(一)

热门文章

  1. SpringBoot+MyBatisPlus+Vue+ElementUI实现前后端分离的物业管理系统
  2. 调度工具之Azkaban 介绍
  3. markdown笔记1--设置字体、颜色、图片、背景色
  4. 基于单片机的触屏电机控制系统的设计
  5. 计算机网络一小时总结 明天考试
  6. KY RD9700_USB网卡驱动
  7. MySQL复制表结构
  8. 那些年,我们一起做过的 Java 课后练习题(71 - 75)
  9. 360全景虚拟现实图片拍摄的注意细节
  10. linux重启数据库11g,linux下重启oracle数据库