【TypeScript】装饰器

在 TypeScript 中,装饰器(Decorators)是一种特殊类型的声明,它允许你通过附加元数据或修改类、方法、属性等的行为来增强或改变它们。装饰器是一种元编程技术,通常用于通过注解方式来简化代码或增加功能,如日志记录、权限控制、缓存等。它是一个实验性特性,基于 ECMAScript 的装饰器提案,TypeScript 对它进行了支持。

装饰器在很多现代框架(如 Angular、NestJS 等)中广泛使用。通过装饰器,你可以对类、类的成员(方法、属性等)或者方法参数进行增强或修改。

1. 装饰器的基本概念

装饰器是一个 函数,它可以被附加到类、类的方法、属性、参数上,并在运行时修改或添加功能。

装饰器的语法

@decoratorName
class MyClass {
  // 类内容
}

装饰器的基本语法是在目标(类、方法、属性、参数)上使用 @ 符号后接装饰器函数名。

2. 装饰器的种类

装饰器可以用在不同的目标上,每种装饰器有不同的功能和签名。TypeScript 支持以下几种常用的装饰器:

  1. 类装饰器(Class Decorators)
  2. 方法装饰器(Method Decorators)
  3. 属性装饰器(Property Decorators)
  4. 参数装饰器(Parameter Decorators)
2.1. 类装饰器(Class Decorators)

类装饰器应用于类定义上,它接受一个类构造函数作为参数。类装饰器通常用于修改类的行为,或为类添加一些元数据。

示例:类装饰器
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

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

const person = new Person("Alice");
console.log(Object.isSealed(person));  // true
  • sealed 是一个类装饰器,它对 Person 类进行了修改,使得类及其原型被“密封”。
  • Object.seal() 方法将对象标记为不可添加或删除属性。

类装饰器的参数是构造函数,因此可以通过修改构造函数的行为来实现更多自定义功能。

2.2. 方法装饰器(Method Decorators)

方法装饰器应用于类的方法。它接受三个参数:

  1. 类的原型(target
  2. 方法名(propertyKey
  3. 方法的属性描述符(descriptor

方法装饰器可以修改方法的行为,增加额外的功能,或者修改方法的属性描述符。

示例:方法装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`Calling ${propertyKey} with arguments: ${args}`);
    return originalMethod.apply(this, args);
  };
}

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

const calc = new Calculator();
calc.add(2, 3);  // Calling add with arguments: [2, 3]
  • log 装饰器用于为 add 方法添加日志功能,记录每次调用该方法时的参数。
2.3. 属性装饰器(Property Decorators)

属性装饰器用于类的属性上,它接受两个参数:

  1. 类的原型(target
  2. 属性名(propertyKey

属性装饰器不能直接修改属性的值,但可以用于为属性添加元数据,或者通过修改类的原型实现类似的效果。

示例:属性装饰器
function logProperty(target: any, propertyKey: string) {
  let value = target[propertyKey];

  const getter = () => {
    console.log(`Getting value of ${propertyKey}: ${value}`);
    return value;
  };

  const setter = (newVal: any) => {
    console.log(`Setting value of ${propertyKey}: ${newVal}`);
    value = newVal;
  };

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

class Person {
  @logProperty
  name: string;

  constructor(name: string) {
    this.name = name;
  }
}

const person = new Person("Alice");
person.name = "Bob";  // Setting value of name: Bob
console.log(person.name);  // Getting value of name: Bob
  • logProperty 装饰器为 name 属性添加了 getter 和 setter,记录属性值的读取和修改。
2.4. 参数装饰器(Parameter Decorators)

参数装饰器应用于方法的参数上,它可以用于记录方法的参数元数据。参数装饰器接受三个参数:

  1. 类的原型(target
  2. 方法名(propertyKey
  3. 参数的索引(parameterIndex
示例:参数装饰器
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
  console.log(`Method ${propertyKey} has parameter at index ${parameterIndex}`);
}

class Person {
  greet(@logParameter name: string) {
    console.log(`Hello, ${name}`);
  }
}

const person = new Person();
person.greet("Alice");  // 输出: Method greet has parameter at index 0
  • logParameter 装饰器用于记录 greet 方法的参数索引。

3. 装饰器的启用

装饰器是一个实验性特性,需要在 tsconfig.json 中启用 experimentalDecorators 选项才能使用。

启用装饰器
{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

4. 装饰器工厂

有时我们希望为装饰器传递参数,可以通过 装饰器工厂 来实现。装饰器工厂是返回装饰器的函数,通常用于自定义装饰器的行为。

示例:装饰器工厂
function addPrefix(prefix: string) {
  return function (target: any, propertyKey: string) {
    console.log(`Adding prefix: ${prefix} to ${propertyKey}`);
  };
}

class Person {
  @addPrefix("Mr.")
  name: string;

  constructor(name: string) {
    this.name = name;
  }
}
  • addPrefix 是一个装饰器工厂,它返回一个装饰器,该装饰器在应用时会添加前缀。

5. 装饰器的组合

多个装饰器可以同时应用于一个目标,装饰器按声明的顺序从下到上依次执行。

示例:装饰器组合
function decoratorA(target: any) {
  console.log("Decorator A");
}

function decoratorB(target: any) {
  console.log("Decorator B");
}

@decoratorA
@decoratorB
class MyClass {}

输出:

Decorator B
Decorator A
  • 装饰器的执行顺序是从下往上,先执行 decoratorB,再执行 decoratorA

6. 装饰器的应用场景

装饰器在许多框架和库中都有广泛应用,常见的应用场景包括:

  1. Angular:用于定义组件、指令、服务等。
  2. NestJS:用于路由处理、请求体验证、身份验证等。
  3. TypeORM:用于定义实体模型、字段映射、索引等。
  4. 日志记录:为方法添加日志功能。
  5. 权限控制:为方法添加权限验证。
  6. 性能监控:记录方法执行时间。

7. 总结

  • 装饰器是 TypeScript 中的一个实验性特性,用于对类、方法、属性、参数等进行增强或修改。
  • 装饰器可以用来简化和规范代码,如日志记录、权限控制、缓存等。
  • 装饰器分为类装饰器方法装饰器属性装饰器参数装饰器等类型。
  • 需要通过配置 experimentalDecorators 选项来启用装饰器。
  • 装饰器是一个强大的元编程工具,广泛应用于现代框架和库中。

装饰器为 TypeScript 提供了更加灵活和可扩展的编程方式,特别适用于注解驱动的开发。

### TypeScript 装饰器概述 装饰器是一种特殊类型的声明,能够附加到类声明、方法、访问器、属性或参数上。它们使用 `@expression` 这样的语法糖衣形式来实现,其中表达式求值后必须返回一个函数,该函数会在运行时被调用并传入相应的上下文。 为了使装饰器生效,项目配置文件 `tsconfig.json` 中需设置 `"experimentalDecorators": true`[^4]。 ### 类装饰器实例 类装饰器应用于类构造函数,通常用来监视、修改或替换类定义。下面是一个简单的例子: ```typescript function logged(constructor: Function) { console.log('Class:', constructor.name); } @logged class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return 'Hello, ' + this.greeting; } } ``` 当创建 `Greeter` 的新实例时,会先执行 `logged` 函数,并打印出类的名字[^1]。 ### 方法装饰器示例 方法装饰器用于修饰原型上的方法。此装饰器接受三个参数:目标对象(对于静态成员来说是类本身;对于实例成员则是类的原型)、成员名字以及描述符。通过这个机制可以在不改动原始逻辑的前提下增强现有行为。 ```typescript // 定义一个简单的方法装饰器 function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } class Example { @enumerable(false) private method() { console.log('This is a non-enumerable method'); } } ``` 在这个案例里,`method()` 将不会出现在枚举操作的结果集中,比如 `for...in` 循环中[^3]。 ### 应用场景说明 利用装饰器模式的优势之一在于能够在不影响原代码结构的情况下增加额外的功能。这不仅提高了代码的可维护性和灵活性,同时也增强了程序设计的表现力和清晰度[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值