装饰器:能够带来额外的信息量,达到分离关注点的目的
- 关注点的问题,在定义某个东西的时候,应该最清楚该东西的情况
- 重复代码的问题
- 问题产生的根源:某些信息在定义时,能够附件的信息量有限
作用:能到为某些属性,类,参数,方法提供元数据信息
本质: 在JS 中,装饰器就是一个函数。(是会参与运行的)
在TS中使用装饰器需要开启”experimentalDecorators”: true
使用装饰器 @装饰器(一个函数)
可以有多个装饰器进行修饰
类装饰器
类装饰的本质是一个函数,该函数接收一个参数,表示类本身(构造函数本身)
将变量定义为类的方法:Function, new () => object
装饰器函数的运行时间,在类定义后直接运行
类装饰器具有的返回值:
- void
- 返回一个新的类,会将新的类替换掉装饰器目标
多个装饰器的情况: 会按照后加入先调用的顺序进行调用
function test(target: new (...args: ang[]) => object){
console.log(target)
}
@test
class U {
loginid:string; //账号,验证规则:1.必填, 2.必须是3-5个字符
loginPwd:string;
}
成员装饰器
属性装饰器是一个函数,该函数需要两个参数;
1. 如果是静态属性,则为类本身,如果是实例属性,则为类的原型<br /> 2. 固定为一个字符串,表示属性名
方法装饰器也是一个函数,该函数需要三个参数:
1. 如果是静态方法,则为类本身,如果是实例方法,则为类的原型<br /> 2.固定为一个字符串,表示方法名<br /> 3. 属性描述对象
function test(target:any,key:string){
console.log(target === A.prototype,key)
}
class A {
@test
prop:string
@test
static name:string
}
类和属性的描述
//装饰器工厂
function classDesciptor(description:string){
return function(target:Function){
//保存到该类的原型之中
target.prototype.$classDescript = description
}
}
function propDescriptior(description:string){
return function (target:any,propName:string){
//把所有属性信息保存在该类的原型中
if(!target.$propDescriptions){
target.$propDescriptions = []
}
target.$propDescriptions.push({
propName,
descriotion
})
}
}
function printObj(obj:object){
//输出类的名字
if(obj.$classDescription){
console.log(obj.$classDescription)
}else{
console.log(Object.getPrototypeof(obj).cunstuctor.name)
}
if(!obj.$propDescriptions){
obj.$propDescriptions = [];
}
//输出所有的属性描述和属性值
for(const key in obj){
if(obj.hasOwnProperty(key)){
const prop = obj.$propDescriptions.find((p:any) => p.propName === key)
if(prop){
console.log('\t${prop.description}:${obj[key]}')
}else{
console.log('\t${key}:${obj[key]}')
}
}
}
}
@classDescriptor("文章")
class Article {
@propDescriptor("标题")
title:string;
@propDescriptor("内容")
content:string;
@propDescriptor("日期")
date:Date;
}
const newAr = new Article();
newAr.title = "好日子"
newAr.content = "今天天气真好"
newAr.date = new Date;
printObj(newAr)
reflect-metadata库
安装 yarn add reflect-metadata
保存元数据的库
https://www.npmjs.com/package/reflect-metadata
import "reflect-metadata"
const key = Symbol.for('desciptor');
function desciptor(description:string){
return Reflect.metadata(key,description)
}
function printObj(obj:object){
const getProtoObj = Object.getPrototypeOf(obj)
//输出类的名字
if(Reflect.hasMetadata(key,getProtoObj)){
console.log(Reflect,getMetadata(key,getProtoObj))
}else{
console.log(getProtoObj.cunstuctor.name)
}
//输出所有的属性描述和属性值
for(const prop in obj){
if(Reflect.hasMetadata(key,obj,prop)){
console.log('\t${Reflect.getMetadata(key,obj,prop)}:${obj[prop]}')
}else{
console.log('\t${prop}:${obj[prop]}')
}
}
}
@desciptor("文章")
class Article {
@desciptor("标题")
title:string;
@desciptor("内容")
content:string;
@desciptor("日期")
date:Date;
}
const newAr = new Article();
newAr.title = "好日子"
newAr.content = "今天天气真好"
newAr.date = new Date;
printObj(newAr)
class-validator
https://www.npmjs.com/package/class-validator
class-transformer
https://www.npmjs.com/package/class-transformer
参数装饰器
依赖注入,依赖倒置
要求函数有三个参数:
- 如果是静态方法,则为类本身,如果是实例方法,则为类的原型
- 方法名称
- 在参数列表中的索引 ```javascript class myMath{ sum(a:number, @test b:number){ return a + b } }
function test(target:any,method:string,index:number){ console.log(target,method,index) }
<a name="xaBWo"></a>
### 关于TS 自动注入的元数据
如果安装了```reflect-metadata```,并且导入了该库,而且在某个成员上添加了元数据,同时也启用了```emitDecoratorMetadata:true```<br />则TS在编译结果中,会将约束的类型,作为元数据加入到对应的位置中<br />可以让TS的类型检查(约束)将有机会在运行时进行。
<a name="vnA2Y"></a>
### AOP
属于面向对象开发的编程方式<br />将一些在业务中共同出现的功能块,横向切分,已达到分离关注点的目的
<a name="WbIXt"></a>
### 类型演算
根据已知的信息,计算出新的类型
三个关键字 :
- typeof : TS中的typeof,书写的位置在类型约束的位置上面就表示获取某 个数据的类型
当typeof作用与类的时候,得到的类型就是该类型的构造函数
```javascript
class U {
name:String,
age:number
}
function createUser(cls: typeof U):U {
return new cls();
}
const Us = createUser(U)
keyof: 作用与类,接口,类型别名(联合类型)用于获取其他类型中的所有成员名组成的联合类型
interface U {
loginId: string
loginPwd: string
name: string
}
function printUser(obj:U, prop: typeof U){
console.log(obj[prop]);
}
const user:U {
loginId:'ssfff',
loginPwd:"11wss",
name:"1122"
}
printUser(user,'name')
in ```javascript interface Article{ title:string, content: string, date: string, }
type Readonly
const A: Readonly
<a name="42e65168"></a>
### TS 类型演算
```javascript
Partial<T> // 将类型T中的成员变成可选
Required<T> // 将类型T中的成员变成必填
Readonly<T> // 将类型T中的成员变成只读
Exclued<T,U> // 提取T中可以赋值给U的类型
NonNullable<T> // 从T中剔除Null 和 undefined
ReturnType<T> // 获取函数返回值类型
InstanceType<T> // 获取构造函数类型的实例类型