TypeScript系列教程十一《装饰器》 -- reflect-metadata
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相关推荐
- TypeScript系列教程十一《装饰器》 -- 属性装饰器
系列教程 TypeScript系列教程一<开篇> TypeScript系列教程二<安装起步> TypeScript系列教程三<基础类型> TypeScript系列教 ...
- jquery系列教程1-选择器全解
全栈工程师开发手册 (作者:栾鹏) 快捷链接: jquery系列教程1-选择器全解 jquery系列教程2-style样式操作全解 jquery系列教程3-DOM操作全解 jquery系列教程4-事件 ...
- TypeScript(八)装饰器
目录 前言 定义 类装饰器 基本用法 操作方式 操作类的原型 类继承操作 方法装饰器 属性装饰器 存取器装饰器 参数装饰器 基本用法 参数过滤器 元数据函数实现 参数过滤 效果实践 装饰器优先级 相同 ...
- TypeScript reflect-metadata 结合方法装饰器实现的一个自定义语法检查的例子
reflect-metadata 例子: import 'reflect-metadata';function validate(target: Object,key: string,descript ...
- 【总结】1277- 重学 TypeScript 系列教程
非常不错的 TypeScript 学习资料,一起推荐给小伙伴们,值得好好看看哈~ 以下是正文. TypeScript 是一种由微软开发的自由和开源的编程语言.它是 JavaScript 的一个超集,而 ...
- Vue中用TypeScript改写JavaScript及装饰器使用
TypeScrpt相比JavaScript的主要特点 多了属性声明类型,格式:属性名:声明类型 name:string=""; //此时name属性声明类型为string 复制代码 ...
- 【Python教程】装饰器的使用及固定模式
装饰器的使用: 在不想修改函数的调用方式,但是想给函数添加内容的功能的时候使用 为什么使用装饰器: 软件实体应该是可扩展,而不可修改的.也就是说,对扩展是开放的,而对修改是封闭的. 因此,引出了开放封 ...
- python基础教程:装饰器的高级应用
装饰器和装饰器模式 装饰器模式是面向对象的一种设计模式,支持将行为动态增加到已经存在的对象上.当装饰一个对象的时候,就表示独立与其他类实例对象,为该对象扩展了新的功能. python的装饰器不是装饰器 ...
- python基础教程:装饰器
1. 函数 在python中,函数通过 def关键字.函数名和可选的参数列表定义.通过 return关键字返回值.我们举例来说明如何定义和调用一个简单的函数: >>> def foo ...
- js系列教程12-浏览器存储全解
全栈工程师开发手册 (作者:栾鹏) 快捷链接: js系列教程1-数组操作全解 js系列教程2-对象和属性全解 js系列教程3-字符串和正则全解 js系列教程4-函数与参数全解 js系列教程5-容器和算 ...
最新文章
- 互联网金融产品需要什么样的产品经理?
- oralce 异常处理 exception
- 按照前序遍历和中序遍历构建二叉树
- C#—Dev XtraTabControl操作总结如动态增加Tab和关闭选项卡方法等
- Nmap 源代码学习四 软件简单使用
- day02:关于惯性导航工具箱的学习与使用:use of the progen
- 使用Spring Task轻松完成定时任务
- 从零开始学习前端JAVASCRIPT — 14、闭包与继承
- Python面试题之python是一种什么语言及优缺点
- 火车头采集器文章伪原创插件工具
- java生成点阵图_点阵字库在JAVA中的实现
- Halcon union_straight_contours_xld详解
- 为什么用conda?
- 2021顶墙十大公认品牌排名榜揭晓
- APP设计尺寸规范大全,APP界面设计新手教程【官方版】
- IDEA 调试技巧,比 Eclipse 强太多了!
- 教你如何在云服务器上安装并配置web服务器(这里以nginx服务器为例,操作系统linux)
- 1G2G3G4G5G:一部波澜壮阔的移动通信史
- jQuery学习笔记(二)使用选择器一
- vue后台管理系统实践方案总结(一)