TypeScript装饰器

在 TypeScript 中,装饰器是一种特殊类型的声明,它可以被附加到类声明、方法、访问符、属性或参数上,以修改类的行为。装饰器通过 @装饰器名 的语法来使用。

装饰器的作用

装饰器主要用于在不改变类本身的情况下,为类添加额外的功能。它可以用来实现日志记录、性能监控、权限控制、数据校验等功能。装饰器是一种函数,它接收三个参数:

  • 对于类来说是类的构造函数
  • 对于属性、方法来说是类的原型对象
  • 对于参数来说是所在方法的参数的索引

装饰器的种类

装饰器分为类装饰器、方法装饰器、属性装饰器和参数装饰器。

类装饰器

类装饰器用来装饰类的构造函数,可以用来监视、修改或替换类定义。一个类装饰器表达式会在运行时当做函数被调用,传入了被装饰的类的构造函数。

function log(target: Function) {
  console.log(target);
}

@log
class Example { }

方法装饰器

方法装饰器用来装饰类中的方法,可以监视、修改或替换方法定义。一个方法装饰器表达式会在运行时当做函数被调用,传入三个参数:对于静态成员是类的构造函数,对于实例成员是类的原型对象,方法的名字和一个描述符。

function enumerable(value: boolean) {
  return function(target: any, key: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}

class Example {
  @enumerable(false)
  method() {}
}

属性装饰器

属性装饰器用来装饰类中的属性,可以监视、修改或替换属性定义。一个属性装饰器表达式会在运行时当做函数被调用,传入两个参数:对于静态成员是类的构造函数,对于实例成员是类的原型对象和属性的名字。

function format(target: any, key: string) {
  let value = target[key];

  const getter = function() {
    return `Formatted: ${value}`;
  };

  const setter = function(newVal: string) {
    value = newVal;
  };

  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true,
  });
}

class Example {
  @format
  value: string = 'initial value';
}

参数装饰器

参数装饰器用来装饰类中的方法参数,可以监视、修改或替换参数定义。一个参数装饰器表达式会在运行时当做函数被调用,传入三个参数:对于静态成员是类的构造函数,对于实例成员是类的原型对象,方法的名字或是构造函数,参数在函数参数列表中的索引。

function logParameter(target: any, key: string, index: number) {
  const metadataKey = `__log_${key}_parameters`;

  if (Array.isArray(target[metadataKey])) {
    target[metadataKey].push(index);
  } else {
    target[metadataKey] = [index];
  }
}

class Example {
  greet(@logParameter message: string): string {
    return message;
  }
}

流程图

flowchart TD
  A(开始)
  A --> B{装饰器种类}
  B --> |类装饰器| C[类的构造函数]
  B --> |方法装饰器| D[类的原型对象]
  B --> |属性装饰器| E[类的原型对象和属性的名字]
  B --> |参数装饰器| F[类的构造函数或原型对象,方法的名字或构造函数,参数的索引]
  F --> G(结束)

关系图

erDiagram
  CLASS ||--o{ METHOD : contains
  CLASS ||--o