TypeScript 记录

94 阅读4分钟

装饰器

@ 符号后面跟的一定是函数或者返回函数

类装饰器

类装饰器接收一个参数,参数是类的本身,所以可以在其原型上新增方法或者属性。有两种返回类型:

  • void:没有返回值时类的行为不会被返回值影响
  • new Class:返回一个新类,原本的类会被替换,一般不这么做,倾向给原型添加方法或者重写原来的方法
const classDecorator:ClassDecorator = (target: Function) => {
  console.log('类装饰器')
  target.prototype.getName = (name:string) => {
    return '装饰器:' + name;
  }
}

function classDecoratorFun (age: number) {
  console.log('工厂函数:', age)

  // return classDecorator
  // 目前只知道以闭包的形式访问工厂函数的变量
  return  (target: Function) => {
    console.log('类装饰器:', age)
    target.prototype.getName = (name:string) => {
      return '装饰器:' + name;
    }
  }
}

// @classDecorator
@classDecoratorFun(18)
class Person {
  public getName(name:string){
    return '类:' + name
  }
}

const p1 = new Person()
console.log(p1.getName('先执行装饰器方法')) //装饰器:先执行装饰器方法

方法装饰器

接收3个参数:原型对象(实例方法)或构造函数(静态方法)、方法名字、成员属性描述符
成员属性描述符:

  • value:方法引用地址,可以用来重写原本方法;
  • writable:true 代表属性可修改;
  • enumerable:true 代表可以枚举,即可以 fou 遍历出成员的键值:getName;
  • configurable:设置是否可设置属性特性,默认为 true。如果为 false,将无法删除该属性,不能够修改属性值,也不能修改属性的属性描述符.注:设置没有效果,原因未知 image.png
const methodDecorator:MethodDecorator = (...args: any[]) => {
  
  //实例方法=>原型对象
  // args[0].testFun() // 调用原型的方法
  // console.log('属性key:', args[1]) // getName
  // args[2]:描述符'
  args[2].value = function () {
    console.log('重写实例方法')
  }
}

function methodDecoratorFun (age: number) {
  console.log('工厂函数:', age)

  // return methodDecorator
  // 目前只知道以闭包的形式访问工厂函数的变量
  return (prop: any, key: string | symbol, desc: PropertyDescriptor) => {
    // 静态方法=>构造函数
    let p2 = new prop('测试2')
    console.log('静态方法=>构造函数:', p2)
    // console.log('属性key:', key) // getName
    desc.value = function () {
      console.log('重写静态方法:', age)
    }
  }
}

class Test {  
  testFun () {
    console.log('调用原型的方法')
  }
}


class Person extends Test {
  name: string;

  constructor (name: string) {
    super()
    this.name = name
  }

  @methodDecorator
  getName(){
    console.log('原来方法:', this.name)
  }

  @methodDecoratorFun(18)
  static getAge (age:number) {
    console.log('静态方法:', age)
  }
}

const p1 = new Person('测试1')
p1.getName()
Person.getAge(28)

属性装饰器

和方法装饰器参数类似,但是第3个参数是 undefined

const propertyDecorator:PropertyDecorator = (...args: any[]) => {
  //实例属性=>原型对象
  args[0].Test()// Test
  console.log('属性key:', args[1]) // name
}

function propertyDecoratorFun (age: number) {
  console.log('工厂函数:', age)

  // return methodDecorator
  // 目前只知道以闭包的形式访问工厂函数的变量
  return (prop: any, key: string | symbol) => {
    // 静态方法=>构造函数
    prop[key] = age
    console.log('静态方法=>构造函数:', prop[key]) // 18
    console.log('属性key:', key) // getName
  }
}

class Person  {
  // @propertyDecorator
  name?: string;

  @propertyDecoratorFun(18)
  static age = 28

  constructor (name: string) {
    this.name = name
  }

  Test () {
    console.log('给原型添加方法')
  }
}

const p1 = new Person('测试1')

参数装饰器

第一个参数和方法装饰器一样,第2个是方法名称而不是参数名称,第三个参数是参数的下标值

const parameterDecorator:ParameterDecorator = (...args: any[]) => {
  //实例方法参数=>原型对象
  console.log(args[0])
  console.log('方法名称:', args[1]) // showInfo
  console.log('参数下标:',args[2]) // 1
}

function parameterDecoratorFun (age: number) {
  console.log('工厂函数:', age)

  // return methodDecorator
  // 目前只知道以闭包的形式访问工厂函数的变量
  return (prop: any, key: string | symbol, index: number) => {
    // 静态方法=>构造函数
    console.log(prop)
    console.log('方法名称:', key) // showInfo
    console.log('参数下标:', index) // 1
  }
}

class Person  {
  name?: string;


  constructor (name: string) {
    this.name = name
  }

  // showInfo (age: number, @parameterDecorator sex: string) {}

  static showInfo (age: number, @parameterDecoratorFun(18) sex: string) {}
}

const p1 = new Person('测试1')

访问装饰器

参数:

  • 静态成员:构造函数,实例成员:原型对象;
  • 成员的名字;
  • 成员的属性描述符 只能作用于 get、set 访问器,属性修饰符的 get、set 只有这种情况才会有值,其他情况 undefine
function getConfigName(descirbe?:string){
    return function(target:any,propertyKey:string,descriptor:PropertyDescriptor){
        const get = descriptor.get
        descriptor.get = function(){
            return `${descirbe||""}${(get as any).call(this)}`
        }
    }
}

class ConfigMan {
    private _name:string
    private _age:number
    constructor(_name:string,_age:number){
        this._name = _name
        this._age = _age
    }
    @getConfigName("这是姓名:")
    get name():string {
        return this._name
    }
    @getConfigName("这是年龄:")
    get age():number {
        return this._age
    }
}

let configMan = new ConfigMan("jack",19)
console.log(configMan.name);
console.log(configMan.age);
>>这是姓名:jack
>>这是年龄:19

内置工具类型:

  • ReturnType:提取函数返回类型
  • ConstructorParameters:提取构造函数参数的类型
  • Parameters:提取函数参数的类型
  • NonNullable:过滤类型中的 null 和 undefined
  • Omit:过滤对象类型中指定的属性类型,代码原理还不理解
  • Pick:和 Omit 相反,提取对象类型中指定属性类型
  • Extract:提取类型交集
  • Exclude:和 Extract 相反
  • Record:定义一个对象类型,Record<string, number>,键是 string,值是 number
  • Readonly:将对象类型的所有属性设为只读,注意顶层属性生效
  • Require:将对象类型的所有可选类型变成必须,注意顶层属性生效
  • Partial:将对象类型的所有必须类型变成可选,注意顶层属性生效

不理解用法

  • ThisType:指定 this 类型
  • OmitThisParameter:移除 this 参数类型
  • ThisParameterType:提取函数类型中 this 参数的类型
  • NoInfer:提醒编译器不进行类型推断
  • InstanceType:提取构造函数类型
  • infer