TypeScript 函数式装饰器及其使用案例
可约束财产
依赖注入
手表装饰师
验证
AJAX 服务
数据加载
在编程中,装饰器通常用于为方法、变量或类添加一些额外的含义/功能。
我在使用 Spring Boot 开发时经常用到装饰器。目前我正在学习 TypeScript,装饰器深深吸引了我。以下是我使用 TypeScript 装饰器来处理函数的一个简单示例。
假设有一个 Human 类,它维护着一个名为 stamina 的属性,该属性会被 run 和 rest 方法操作。我们需要在 run 和 rest 这两个操作前后分别获取 stamina 的值。我提供了使用和不使用装饰器的代码片段。
装饰器之前的代码
class Human {
stamina: number;
constructor(stamina: number) {
this.stamina = stamina;
}
run(requiredStamina: number): number {
return (this.stamina -= requiredStamina);
}
rest(addedStamina: number): number {
return (this.stamina += addedStamina);
}
}
const human = new Human(10);
console.log(`Stamina before run: ` + human.stamina);
human.run(1);
console.log(`Stamina after run: ` + human.stamina);
console.log(`Stamina before rest: ` + human.stamina);
human.rest(12);
console.log(`Stamina after rest: ` + human.stamina);
console.log(`Stamina before run: ` + human.stamina);
human.run(20);
console.log(`Stamina after run: ` + human.stamina);
// Stamina before run: 10
// Stamina after run: 9
// Stamina before rest: 9
// Stamina after rest: 21
// Stamina before run: 21
// Stamina after run: 1
上面的代码看起来不错,但很快文件就会充斥着大量样板代码。
使用装饰器编写代码
class Human {
stamina: number;
constructor(stamina: number) {
this.stamina = stamina;
}
@log
run(requiredStamina: number): number {
return (this.stamina -= requiredStamina);
}
@log
rest(addedStamina: number): number {
return (this.stamina += addedStamina);
}
}
function log(
target: Object,
propertyKey: string,
descriptor: TypedPropertyDescriptor<any>
) {
const originalMethod = descriptor.value; // save a reference to the original method
// NOTE: Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method (see notes below)
descriptor.value = function (...args: any[]) {
// pre
console.log(`Stamina before ${propertyKey}: ` + args);
// run and store result
const result = originalMethod.apply(this, args);
// post
console.log(`Stamina after ${propertyKey}: ` + result);
// return the result of the original method (or modify it before returning)
return result;
};
return descriptor;
}
const human = new Human(10);
human.run(1);
human.rest(12);
human.run(20);
// Stamina before run: 1
// Stamina after run: 9
// Stamina before rest: 12
// Stamina after rest: 21
// Stamina before run: 20
// Stamina after run: 1
我在代码片段中添加了注释,解释了装饰器中的数据流!简而言之,装饰器会在函数调用之前执行,并且可以访问函数的参数和返回值,供装饰器使用。
装饰器通常有很多用例。请在评论中告诉我一些有趣的用例,或者通过radnerus93联系我。
文章来源:https://dev.to/radnerus/typescript-function-decorators-w-usecases-1a8g