【专项学习】 —— Typescript高级语法

一、类的装饰器

①package.json中添加dev命令

"dev": "ts-node ./src/index.ts"

②tsconfig.json中把实验类型的支持打开

    "experimentalDecorators": true,  
    "emitDecoratorMetadata": true,

③使用多个装饰器,从上到下(从左到右)收集装饰器,从下到上(从右到左)执行装饰器  

//类的装饰器
//装饰器本身是一个函数
//类装饰器接受的参数是构造函数
//装饰器通过 @ 符号来使用

function testDecorator(constructor: any) {
  // constructor.prototype.getName = () => {
  //   console.log('dell');
  // }
  console.log('decorator');
}

function testDecorator1(constructor: any) {
  console.log('decorator1');
}

//装饰器会在类创建好之后立即执行,对类做一些装饰
@testDecorator
@testDecorator1
class Test {}

const test = new Test();
// (test as any).getName();

 

 ④定义函数,使用工厂模式返回装饰器,使得在满足一定条件后才会执行装饰器

function testDecorator(flag: boolean){
   if(flag) {
    return function (constructor: any) {
      constructor.prototype.getName = () => {
        console.log('dell');
      }
    }
   }else{
    return function (constructor: any) {};
   }
}

@testDecorator(true)
class Test {}

const test = new Test();
(test as any).getName();

⑤constructor类型由any类型改为定义为泛型T

// new后面是一个构造函数,接收很多参数,每一个参数的类型是any,返回的是一个any类型的内容
// T 类型可以被这个构造函数实例化出来
function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
    return class extends constructor {
       name = 'lee';
       getName() {
         return this.name;
       }
    };
}

@testDecorator
class Test {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

const test = new Test('dell');
console.log((test as any).getName())

⑥解决test无法直接调用getName —— test.getName()会报错  

function testDecorator() {
  return function<T extends new (...args: any[]) => any>(constructor: T) {
    return class extends constructor {
       name = 'lee';
       getName() {
         return this.name;
       }
    };
  };
}

//执行结果返回的装饰器,修饰class
const Test = testDecorator()(class {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
})

const test = new Test('dell');
console.log(test.getName())

 

二、方法装饰器  

//装饰器 永远都是一个函数

//普通方法, target对应的是类的prototype
//静态方法,target对应的是类的构造函数

//和Object.defineProperty类似
//Object.defineProperty(obj, prop, descriptor)
//参数:原型对象,属性,(descriptor保存着)控制函数的一些属性

function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
  //允许修改原始方法
  // descriptor.writable = true;
  //修改原始方法的值
  descriptor.value = function () {
    return 'decorator';
  }
}

class Test {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  @getNameDecorator
  getName() {
    return this.name;
  }
}

const test = new Test('dell');
// test.getName = () => {
//   return '123';
// }
console.log(test.getName());

 

三、访问器的装饰器  

function visitDecorator(target: any, key: string, descriptor: PropertyDescriptor){
  // 访问器不允许重写修改
  // descriptor.writable = false;
}

class Test {
  private _name: string;
  constructor(name: string) {
    this._name = name;
  }
  //Getter 访问器
  get name() {
    return this._name;
  }
  @visitDecorator
  set name(name: string) {
    this._name = name;
  }
}

const test = new Test('dell');
test.name = '123123123123';
console.log(test.name);

  

四、属性的装饰器  

// function nameDecorator(target: any, key: string): any{
//   const descriptor: PropertyDescriptor = {
//     writable: false
//   };
//   return descriptor; //会替换掉name属性的descriptor
// }

//修改的并不是实例上的name,而是原型上的name
function nameDecorator(target: any, key: string): any{
  target[key] = 'lee';
}

//name 放在实例上
class Test {
  @nameDecorator
  name = 'Dell';
}

const test = new Test();
// test.name = 'dell lee';
// console.log(test.name);    // Dell
console.log((test as any).__proto__.name);  // lee

 

五、参数装饰器  

// 原型, 方法名, 参数所在的位置
function paramDecorator(target: any, method: string, paramIndex: number){
   console.log(target, method, paramIndex)
}

class Test {
  getInfo( name: string, @paramDecorator age: number) {
    console.log(name, age);
  }
}

const test = new Test();
test.getInfo('Dell', 30);

  

 

 

六、装饰器实际使用的小例子

const userInfo: any = undefined;

//工厂模式写方法装饰器,解决代码复用中方法不同打印结果不同
function catchError(msg: string) {
  return function (target: any, key: string, descriptor: PropertyDescriptor){
    const fn = descriptor.value;
    descriptor.value = function() {
      try {
        fn();
      }catch(e) {
        console.log(msg)
      }
    }
 }
}


class Test {
  @catchError('userInfo.name不存在')
  getName() {
    // try{
    //   return userInfo.name
    // }catch(e) {
    //   console.log('userInfo.name 不存在')
    // }
    return userInfo.name
  }
  @catchError('userInfo.age不存在')
  getAge() {
    // try{
    //   return userInfo.age
    // }catch(e) {
    //   console.log('userInfo.age 不存在')
    // }
    return userInfo.age
  }
}

const test = new Test();
test.getName();
test.getAge();

  

 


注:课程源自慕课网 

posted @ 2021-03-12 16:15  柳洁琼Elena  阅读(138)  评论(0编辑  收藏  举报