如何创建自定义 TypeScript 装饰器

装饰器是 TypeScript 中的一项功能,允许在运行时修改类、方法、属性或参数。它们是提供元编程功能的特殊函数。在 TypeScript 中,装饰器通常用于 Angular 等框架中以增强功能。本文将逐步介绍如何创建自定义装饰器。

TypeScript 中的装饰器类型

TypeScript 中有四种主要类型的装饰器:

  • 类装饰器
  • 方法装饰器
  • 访问器装饰器
  • 属性装饰器

在 TypeScript 中启用装饰器

要在 TypeScript 项目中使用装饰器,必须在 tsconfig.json 文件中启用 experimentalDecorators 选项。

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

创建类装饰器

类装饰器应用于类的构造函数。它们可用于向类添加元数据或功能。以下是如何创建简单类装饰器的示例。

function logClass(constructor: Function) {
  console.log(`Class ${constructor.name} is created`);
}

@logClass
class Person {
  constructor(public name: string) {}
}

const person = new Person("John");
// Output: Class Person is created

创建方法装饰器

方法装饰器应用于类方法。它们可用于修改或观察方法的行为。下面是一个记录方法执行情况的方法装饰器示例。

function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Method ${propertyKey} is called with arguments:`, args);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Calculator {
  @logMethod
  add(a: number, b: number) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3); 
// Output: Method add is called with arguments: [2, 3]

创建属性装饰器

属性装饰器可用于观察或修改属性。以下是属性装饰器确保属性具有默认值的示例。

function defaultValue(value: any) {
  return function (target: any, propertyKey: string) {
    let propertyValue = value;

    const getter = function () {
      return propertyValue;
    };

    const setter = function (newValue: any) {
      propertyValue = newValue || value;
    };

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

class User {
  @defaultValue('Anonymous')
  name!: string;
}

const user = new User();
console.log(user.name); // Output: Anonymous
user.name = 'Alice';
console.log(user.name); // Output: Alice

创建参数装饰器

参数修饰器应用于方法的参数。它们对于验证或记录参数等任务很有用。以下是参数修饰器的示例。

function logParameter(target: any, propertyKey: string, parameterIndex: number) {
  console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} is being decorated`);
}

class Vehicle {
  drive(@logParameter speed: number) {
    console.log(`Driving at speed ${speed}`);
  }
}

const vehicle = new Vehicle();
vehicle.drive(50);
// Output: Parameter at index 0 in method drive is being decorated

结论

TypeScript 中的装饰器提供了强大的元编程功能,可以增强和扩展类、方法和属性的功能。通过使用自定义装饰器,可以创建可重复使用、高效且有组织的代码结构。本指南演示了如何创建不同类型的装饰器:类、方法、属性和参数。