装饰器:能够带来额外的信息量,达到分离关注点的目的

  • 关注点的问题,在定义某个东西的时候,应该最清楚该东西的情况
  • 重复代码的问题
  • 问题产生的根源:某些信息在定义时,能够附件的信息量有限

作用:能到为某些属性,类,参数,方法提供元数据信息
本质: 在JS 中,装饰器就是一个函数。(是会参与运行的)
在TS中使用装饰器需要开启”experimentalDecorators”: true
使用装饰器 @装饰器(一个函数)
可以有多个装饰器进行修饰

类装饰器

类装饰的本质是一个函数,该函数接收一个参数,表示类本身(构造函数本身)
将变量定义为类的方法:Function, new () => object
装饰器函数的运行时间,在类定义后直接运行

类装饰器具有的返回值:

  • void
  • 返回一个新的类,会将新的类替换掉装饰器目标

多个装饰器的情况: 会按照后加入先调用的顺序进行调用

  1. function test(target: new (...args: ang[]) => object){
  2. console.log(target)
  3. }
  4. @test
  5. class U {
  6. loginid:string; //账号,验证规则:1.必填, 2.必须是3-5个字符
  7. loginPwd:string;
  8. }

成员装饰器

  • 属性装饰器是一个函数,该函数需要两个参数;

    1. 1. 如果是静态属性,则为类本身,如果是实例属性,则为类的原型<br /> 2. 固定为一个字符串,表示属性名
  • 方法装饰器也是一个函数,该函数需要三个参数:

    1. 1. 如果是静态方法,则为类本身,如果是实例方法,则为类的原型<br /> 2.固定为一个字符串,表示方法名<br /> 3. 属性描述对象
    1. function test(target:any,key:string){
    2. console.log(target === A.prototype,key)
    3. }
    4. class A {
    5. @test
    6. prop:string
    7. @test
    8. static name:string
    9. }

    类和属性的描述

  1. //装饰器工厂
  2. function classDesciptor(description:string){
  3. return function(target:Function){
  4. //保存到该类的原型之中
  5. target.prototype.$classDescript = description
  6. }
  7. }
  8. function propDescriptior(description:string){
  9. return function (target:any,propName:string){
  10. //把所有属性信息保存在该类的原型中
  11. if(!target.$propDescriptions){
  12. target.$propDescriptions = []
  13. }
  14. target.$propDescriptions.push({
  15. propName,
  16. descriotion
  17. })
  18. }
  19. }
  20. function printObj(obj:object){
  21. //输出类的名字
  22. if(obj.$classDescription){
  23. console.log(obj.$classDescription)
  24. }else{
  25. console.log(Object.getPrototypeof(obj).cunstuctor.name)
  26. }
  27. if(!obj.$propDescriptions){
  28. obj.$propDescriptions = [];
  29. }
  30. //输出所有的属性描述和属性值
  31. for(const key in obj){
  32. if(obj.hasOwnProperty(key)){
  33. const prop = obj.$propDescriptions.find((p:any) => p.propName === key)
  34. if(prop){
  35. console.log('\t${prop.description}:${obj[key]}')
  36. }else{
  37. console.log('\t${key}:${obj[key]}')
  38. }
  39. }
  40. }
  41. }
  42. @classDescriptor("文章")
  43. class Article {
  44. @propDescriptor("标题")
  45. title:string;
  46. @propDescriptor("内容")
  47. content:string;
  48. @propDescriptor("日期")
  49. date:Date;
  50. }
  51. const newAr = new Article();
  52. newAr.title = "好日子"
  53. newAr.content = "今天天气真好"
  54. newAr.date = new Date;
  55. printObj(newAr)

reflect-metadata库

安装 yarn add reflect-metadata
保存元数据的库
https://www.npmjs.com/package/reflect-metadata

  1. import "reflect-metadata"
  2. const key = Symbol.for('desciptor');
  3. function desciptor(description:string){
  4. return Reflect.metadata(key,description)
  5. }
  6. function printObj(obj:object){
  7. const getProtoObj = Object.getPrototypeOf(obj)
  8. //输出类的名字
  9. if(Reflect.hasMetadata(key,getProtoObj)){
  10. console.log(Reflect,getMetadata(key,getProtoObj))
  11. }else{
  12. console.log(getProtoObj.cunstuctor.name)
  13. }
  14. //输出所有的属性描述和属性值
  15. for(const prop in obj){
  16. if(Reflect.hasMetadata(key,obj,prop)){
  17. console.log('\t${Reflect.getMetadata(key,obj,prop)}:${obj[prop]}')
  18. }else{
  19. console.log('\t${prop}:${obj[prop]}')
  20. }
  21. }
  22. }
  23. @desciptor("文章")
  24. class Article {
  25. @desciptor("标题")
  26. title:string;
  27. @desciptor("内容")
  28. content:string;
  29. @desciptor("日期")
  30. date:Date;
  31. }
  32. const newAr = new Article();
  33. newAr.title = "好日子"
  34. newAr.content = "今天天气真好"
  35. newAr.date = new Date;
  36. 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) }

  1. <a name="xaBWo"></a>
  2. ### 关于TS 自动注入的元数据
  3. 如果安装了```reflect-metadata```,并且导入了该库,而且在某个成员上添加了元数据,同时也启用了```emitDecoratorMetadata:true```<br />则TS在编译结果中,会将约束的类型,作为元数据加入到对应的位置中<br />可以让TS的类型检查(约束)将有机会在运行时进行。
  4. <a name="vnA2Y"></a>
  5. ### AOP
  6. 属于面向对象开发的编程方式<br />将一些在业务中共同出现的功能块,横向切分,已达到分离关注点的目的
  7. <a name="WbIXt"></a>
  8. ### 类型演算
  9. 根据已知的信息,计算出新的类型
  10. 三个关键字 :
  11. - typeof : TS中的typeof,书写的位置在类型约束的位置上面就表示获取某 个数据的类型
  12. 当typeof作用与类的时候,得到的类型就是该类型的构造函数
  13. ```javascript
  14. class U {
  15. name:String,
  16. age:number
  17. }
  18. function createUser(cls: typeof U):U {
  19. return new cls();
  20. }
  21. const Us = createUser(U)
  • keyof: 作用与类,接口,类型别名(联合类型)用于获取其他类型中的所有成员名组成的联合类型

    1. interface U {
    2. loginId: string
    3. loginPwd: string
    4. name: string
    5. }
    6. function printUser(obj:U, prop: typeof U){
    7. console.log(obj[prop]);
    8. }
    9. const user:U {
    10. loginId:'ssfff',
    11. loginPwd:"11wss",
    12. name:"1122"
    13. }
    14. printUser(user,'name')
  • in ```javascript interface Article{ title:string, content: string, date: string, }

type Readonly = { readonly [p in keyof T]: T[p] } type Partial = { [p in keyof T]?: T[p] }

const A: Readonly

= { title:’晋级赛’, content:”方法法国”, date:”2022年8月25日16:05:45” }

  1. <a name="42e65168"></a>
  2. ### TS 类型演算
  3. ```javascript
  4. Partial<T> // 将类型T中的成员变成可选
  5. Required<T> // 将类型T中的成员变成必填
  6. Readonly<T> // 将类型T中的成员变成只读
  7. Exclued<T,U> // 提取T中可以赋值给U的类型
  8. NonNullable<T> // 从T中剔除Null 和 undefined
  9. ReturnType<T> // 获取函数返回值类型
  10. InstanceType<T> // 获取构造函数类型的实例类型