返回

TypeScript 中的装饰器 Decorator

前端

引言

在 JavaScript 生态系统中,装饰器是一种强大的工具,它允许我们以一种声明式的方式修改类的行为。在 TypeScript 中,装饰器得到了进一步的增强,为我们提供了更多控制和灵活性。本文将深入探讨 TypeScript 中的装饰器,介绍它们的语法、功能和一些常见的用例。

装饰器的语法

装饰器是在类声明之前使用 @ 符号应用的函数或表达式。它们可以接受一个或多个参数,这些参数将传递给装饰器函数。例如:

@decorator
class MyClass {}

装饰器函数本身必须返回一个类型为 ClassDecoratorPropertyDecoratorMethodDecorator 的对象。这三个类型用于指定装饰器的作用域,分别对应于类、属性和方法。

装饰器的功能

装饰器允许我们对类的行为进行各种修改,包括:

  • 修改类本身: 例如,我们可以使用装饰器来添加元数据、实现接口或修改类的原型。
  • 修改类成员: 我们可以使用装饰器来修改属性或方法的符、访问控制或行为。
  • 注入依赖: 我们可以使用装饰器来实现依赖注入,从而使代码更加模块化和可测试。

装饰器的用例

装饰器在 TypeScript 中有广泛的用例,其中一些常见用例包括:

  • 元数据管理: 我们可以使用装饰器来存储有关类的附加信息,例如作者、版本或文档。
  • 属性验证: 我们可以使用装饰器来验证属性的值,确保它们符合某些约束。
  • 依赖注入: 我们可以使用装饰器来注入依赖项,从而消除硬编码的依赖关系并提高代码的可测试性。
  • 方法拦截: 我们可以使用装饰器来拦截方法调用,例如记录调用或实现缓存机制。

实现一个简单的 DI 依赖注入例子

为了演示装饰器的使用,让我们实现一个简单的依赖注入例子。我们将创建一个 UserService,该服务需要一个 UserRepository 依赖项。我们可以使用装饰器来注入这个依赖项,如下所示:

class UserRepository {}

@Injectable()
class UserService {
  private userRepository: UserRepository;

  constructor(@Inject() userRepository: UserRepository) {
    this.userRepository = userRepository;
  }
}

// 创建一个装饰器来注入依赖项
function Injectable() {
  return function(target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
    const originalConstructor = target.constructor;
    const newConstructor = function(...args: any[]) {
      const instance = new originalConstructor(...args);
      instance[propertyKey] = new UserRepository();
      return instance;
    };
    newConstructor.prototype = originalConstructor.prototype;
    Object.defineProperty(target, 'constructor', {
      value: newConstructor,
      enumerable: false,
      configurable: true,
      writable: true
    });
  };
}

在这个例子中,@Injectable() 装饰器会在类构造函数上执行,并注入 UserRepository 依赖项。这样,我们就可以在 UserService 的构造函数中通过 @Inject() 装饰器接收该依赖项。

结论

装饰器是 TypeScript 中一项强大的工具,它允许我们以声明式的方式修改类的行为。通过装饰器,我们可以实现元数据管理、属性验证、依赖注入、方法拦截等各种功能。充分利用装饰器,可以极大地提高代码的可重用性、可维护性和可测试性。