装饰器标准实现
00:00
TypeScript Stage 3装饰器标准实现详解:类装饰器、方法装饰器与元数据。
1. Stage 3 装饰器概述
1.1 与旧版装饰器的区别
| 特性 | Legacy (experimental) | Stage 3 (standard) |
|---|---|---|
| 启用方式 | experimentalDecorators | 默认支持 |
| API 风格 | 基于函数描述符 | 基于上下文对象 |
| 类型安全 | 较弱 | 强 |
| 元数据 | 需要 emitDecoratorMetadata | 内置 metadata |
1.2 启用方式
{
"compilerOptions": {
// Stage 3 装饰器无需额外配置
// 旧版需要:
// "experimentalDecorators": true
}
}
2. 类装饰器
function logged<T extends { new (...args: any[]): {} }>(value: T, context: ClassDecoratorContext) {
const name = context.name;
return class extends value {
constructor(...args: any[]) {
console.log(`Creating ${String(name)} with args:`, args);
super(...args);
}
};
}
@logged
class User {
constructor(public name: string) {}
}
new User('Alice'); // Creating User with args: ['Alice']
3. 方法装饰器
function debounce(delay: number) {
return function (value: Function, context: ClassMethodDecoratorContext) {
let timer: ReturnType<typeof setTimeout>;
return function (this: any, ...args: any[]) {
clearTimeout(timer);
timer = setTimeout(() => value.call(this, ...args), delay);
};
};
}
class Search {
@debounce(300)
handleInput(query: string) {
console.log('Searching:', query);
}
}
4. 属性装饰器
function required(value: undefined, context: ClassFieldDecoratorContext) {
return function (this: any, initialValue: any) {
if (initialValue === undefined || initialValue === null) {
throw new Error(`${String(context.name)} is required`);
}
return initialValue;
};
}
class User {
@required
name: string;
constructor(name: string) {
this.name = name;
}
}
5. 元数据
function route(path: string) {
return function (value: Function, context: ClassMethodDecoratorContext) {
context.metadata.routes ??= {};
context.metadata.routes[context.name] = path;
};
}
class ApiController {
@route('/users')
getUsers() {}
@route('/users/:id')
getUser() {}
}
6. 装饰器组合
// 多个装饰器从下到上执行(类似函数组合)
@log
@validate
@memoize
class Calculator {
@debounce(100)
@throttle(50)
calculate() {}
}