装饰器是一种特殊的声明,可以附加到类、方法、访问器、属性或参数上。装饰器使用 @expression 形式,是一种元编程的方式。
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
// 类装饰器函数
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
}
// 装饰器工厂
function classDecorator(value: string) {
return function(constructor: Function) {
console.log(`Class decorator: ${value}`);
};
}
@classDecorator("test")
class MyClass {}
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`Result:`, result);
return result;
};
return descriptor;
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3);
// 输出:
// Calling add with args: [2, 3]
// Result: 5
function configurable(value: boolean) {
return function(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
descriptor.configurable = value;
};
}
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() {
return this._x;
}
@configurable(false)
get y() {
return this._y;
}
}
function format(formatString: string) {
return function(target: any, propertyKey: string) {
let value: string;
const getter = function() {
return value;
};
const setter = function(newVal: string) {
value = `${formatString} ${newVal}`;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
};
}
class Greeter {
@format("Hello,")
greeting: string;
}
const greeter = new Greeter();
greeter.greeting = "World";
console.log(greeter.greeting); // "Hello, World"
function required(target: any, propertyKey: string, parameterIndex: number) {
const existingRequiredParameters: number[] =
Reflect.getOwnMetadata("required", target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata("required", existingRequiredParameters, target, propertyKey);
}
function validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = function(...args: any[]) {
const requiredParameters: number[] =
Reflect.getOwnMetadata("required", target, propertyKey) || [];
for (const parameterIndex of requiredParameters) {
if (parameterIndex >= args.length || args[parameterIndex] === undefined) {
throw new Error("Missing required argument");
}
}
return method.apply(this, args);
};
}
class Greeter {
@validate
greet(@required name: string) {
return `Hello, ${name}`;
}
}
多个装饰器可以应用到同一个声明上:
function first() {
console.log("first(): factory evaluated");
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("first(): called");
};
}
function second() {
console.log("second(): factory evaluated");
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("second(): called");
};
}
class ExampleClass {
@first()
@second()
method() {}
}
// 输出顺序:
// first(): factory evaluated
// second(): factory evaluated
// second(): called
// first(): called
// 性能监控装饰器
function measure(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args: any[]) {
const start = performance.now();
const result = await originalMethod.apply(this, args);
const end = performance.now();
console.log(`${propertyKey} took ${end - start}ms`);
return result;
};
return descriptor;
}
// 缓存装饰器
function memoize(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
const cache = new Map();
descriptor.value = function(...args: any[]) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = originalMethod.apply(this, args);
cache.set(key, result);
return result;
};
return descriptor;
}
// 权限检查装饰器
function authorize(role: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
if (!checkUserRole(role)) {
throw new Error("Unauthorized");
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
class UserService {
@measure
@memoize
async getUser(id: number) {
// 获取用户数据
}
@authorize("admin")
deleteUser(id: number) {
// 删除用户
}
}