TypeScript装饰器

一、TypeScript装饰器介绍

装饰器是一种通过添加标注的方式来对类型进行扩展的工具。它可以让我们在方法属性参数等各种数据上进行扩展,从而提高代码的可读性扩展性。本文将介绍 TypeScript 装饰器的基本语法和具体使用方法。

1. 装饰器的作用

  • 只能在类中使用
  • 减少冗余代码量
  • 提高代码扩展性

2. 装饰器的语法

装饰器本质上就是一个函数,在特定的位置调用装饰器函数即可对数据进行扩展。下面是一个装饰器函数的基本语法:

function myDecorator(target: any) {
  // 对 target 进行处理
}

其中,target 表示要扩展的数据,可以是方法属性参数等。

二、装饰器的具体使用方法

1. 类装饰器

  • 在类上添加 name 和 eat 属性
namespace a {
  function addNameEat(constructor: Function):void {
    constructor.prototype.name = "tom";
    constructor.prototype.eat = () => {};
  };
  
  @addNameEat
  class Person {
    name: string;
    eat: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name); // tom
  p.eat();
}

2. 装饰器工厂

  • 通过装饰器工厂传递参数
namespace b {
  function addNameEatFactory(name: string):Function {
    return function addNameEat(constructor: Function):void {
      constructor.prototype.name = name;
      constructor.prototype.eat = () => {};
    };
  };
  @addNameEatFactory('Jerry')
  class Person {
    name: string;
    eat: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name); // Jerry
  p.eat();
}

3. 装饰器替换类

  • 使用装饰器替换类
namespace c {
  function replaceClass(constructor: Function) {
    return class {
      // 由于类型安全,此处的属性只能多不能少
      name: string = 'tom';
      eat: Function = () => {};
      constructor() {}
    }
  };
  @replaceClass
  class Person {
    name: string;
    eat: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name); // tom
  p.eat();
}

4. 属性、方法装饰器

  • 属性、方法装饰器
namespace d {
  // 如果装饰的是实例属性的话,target是构造函数的原型
  function upperCase(target: any, propertyKey: string) {
    // console.log(target, propertyKey); // { getName: [Function (anonymous)], sun: [Function (anonymous)] } name
    let value = target[propertyKey]
    const getter = () => value;
    const setter = (newVal: string) => { value = val.toUpperCase(); };
    if (delete target[propertyKey]) {
      Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
      });
    }
  }
  // 如果装饰的是静态属性,target就是构造函数
  function staticPrototypeDecorator(target: any, propertyKey: string) {
    // console.log(target, propertyKey); // [Function: Person] { age: 18 } age
  }
  function noEnumerable(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = false; // 不可枚举
  }
  function toNumber(target: any, propertyKey, descriptor: PropertyDescriptor) {
    let oldMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      args = args.map(item => parseFloat(item));
      return oldMethod.apply(this, args)
    }
  }
  class Person {
    @upperCase
    name: string = 'jerry';   // 实例属性
    @staticPrototypeDecorator
    static age: number = 18;  // 静态属性
    @noEnumerable
    getName() { console.log(this.name); }; // 实例方法
    @toNumber
    sum(...args: any[]) { // 实例方法
      return args.reduce((prev: number, next: number) => prev + next, 0);
    }
  }
  let p = new Person();
  console.log(p.name); // JERRY
  console.log(p.sum('1', '2', '3', '4')); // 10
}

5. 参数装饰器

  • 参数装饰器
namespace e {
  // target:静态属性指构造函数,实例属性、实例方法值构造函数的原型
  // methodName:方法的名称
  // paramIndex:参数的索引
  function addAge(target: any, methodName: string, paramIndex: number) {
    // console.log(target, methodName, paramIndex); // { login: [Function (anonymous)] } login 1
    target.age = 18;
  }
  class Person {
    age: number;
    login(username: string, @addAge password: string) {
      console.log(this.age, username, password); // 18 admin admin123
    }
  }
  let p = new Person();
  p.login('admin', 'admin123');
}

6. 装饰器执行顺序

  • class装饰器最后执行,后写的类装饰器先执行
  • 方法和参数中的装饰器,参数装饰器先执行,再执行方法装饰器
  • 方法和属性装饰器,谁在前面先执行谁
  • 先内后外 先上后下执行
namespace f {
  function ClassDecorator1() {
    return function (target) {
      console.log('ClassDecorator1');
    }
  }
  function ClassDecorator2() {
    return function (target) {
      console.log('ClassDecorator2');
    }
  }
  function PropertyDecorator(name: string) {
    return function (target, propertyName) {
      console.log('PropertyDecorator', propertyName, name);
    }
  }
  function MethodDecorator() {
    return function (target, propertyName) {
      console.log('MethodDecorator', propertyName);
    }
  }
  function ParameterDecorator() {
    return function (target, propertyName, index) {
      console.log('ParameterDecorator', propertyName, index);
    }
  }
  @ClassDecorator1()
  @ClassDecorator2()
  class Person {
    @PropertyDecorator('name')
    name: string = '';
    @PropertyDecorator('age')
    age: string = '';
    @MethodDecorator()
    hello(@ParameterDecorator() hello: string, @ParameterDecorator() word: string) {}
  }
}

输出顺序为:

// 打印顺序
PropertyDecorator name name
PropertyDecorator age age
ParameterDecorator hello 1
ParameterDecorator hello 0
MethodDecorator hello
ClassDecorator2
ClassDecorator1

7、装饰器的应用场景

装饰器在代码中有许多应用场景。以下是一些常见的用例:

日志记录:在方法或类上添加日志功能,用于记录方法的执行过程和结果。

性能监控:在方法或类上添加性能监控功能,用于计算方法的执行时间。

权限验证:在方法或类上添加权限验证功能,用于检查用户是否有权执行某个操作。

数据验证:在方法或类上添加数据验证功能,用于检查输入数据是否合法。

缓存处理:在方法或类上添加缓存处理功能,用于缓存方法的结果。

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
TypeScript装饰器是一种特殊的语法,用于修改类、方法、属性或参数的行为。装饰器通过在目标声明之前使用@符号来应用。装饰器可以用来添加新的功能、修改行为或元数据。 装饰器可以应用于类、方法、属性和参数。例如,可以使用装饰器来为类添加日志记录、验证或路由等功能。 下面是一个示例,演示如何使用装饰器来添加日志记录功能: ```typescriptfunction log(target: any, name: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling ${name} with arguments: ${JSON.stringify(args)}`); const result = originalMethod.apply(this, args); console.log(`Method ${name} returned: ${JSON.stringify(result)}`); return result; }; return descriptor; } class MyClass { @log myMethod(arg: string) { return `Hello, ${arg}!`; } } const instance = new MyClass(); instance.myMethod("World"); ``` 在上面的示例中,我们定义了一个名为log的装饰器函数。该装饰器函数接收三个参数:目标对象、方法名和属性描述符。我们通过修改属性描述符的value来修改原始方法的行为,添加了日志记录的功能。 然后,我们将装饰器应用于MyClass类的myMethod方法。当调用myMethod方法时,会自动触发装饰器中定义的日志记录逻辑。 通过使用装饰器,我们可以轻松地修改类的行为,而无需在每个方法中手动添加相同的功能。这样可以提高代码的可重用性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值