TypeScript装饰器详解:从基础到应用

TypeScript 中的装饰器(Decorators)是一种特殊类型的声明,它可以被附加到类声明、方法、访问器、属性或参数上,以修改类的行为。装饰器使用 @expression
的形式,其中 expression
必须是一个函数,它会在运行时被调用,并以被装饰的声明作为参数。
装饰器的基本概念
装饰器本质上是一个函数,它接收三个参数:
- target: 对于类装饰器,
target
是类的构造函数;对于方法装饰器,target
是类的原型;对于属性装饰器,target
是类的原型或类的构造函数(取决于装饰的是实例属性还是静态属性)。 - key: 被装饰的属性或方法的名称。
- descriptor: 对于方法装饰器,
descriptor
是属性描述符(PropertyDescriptor);对于属性装饰器,descriptor
是undefined
。
装饰器的类型
- 类装饰器:应用于类构造函数,可以用来观察、修改或替换类定义。
- 方法装饰器:应用于类的方法,可以用来修改方法的行为。
- 访问器装饰器:应用于类的访问器(getter/setter),可以用来修改访问器的行为。
- 属性装饰器:应用于类的属性,可以用来修改属性的行为。
- 参数装饰器:应用于方法的参数,可以用来修改参数的行为。
装饰器的应用场景
-
日志记录:通过方法装饰器,可以在方法执行前后自动记录日志。
function log(target: any, key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling ${key} with`, args); const result = originalMethod.apply(this, args); console.log(`Called ${key}, returned`, result); return result; }; return descriptor; } class MyClass { @log myMethod(arg: string) { return `Hello, ${arg}`; } } const instance = new MyClass(); instance.myMethod('World'); // Logs: Calling myMethod with ['World'], Called myMethod, returned Hello, World
-
权限控制:通过方法装饰器,可以在方法执行前检查用户权限。
function checkPermission(role: string) { return function (target: any, key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { if (role === 'admin') { return originalMethod.apply(this, args); } else { throw new Error('Permission denied'); } }; return descriptor; }; } class MyClass { @checkPermission('admin') adminMethod() { return 'Admin access granted'; } } const instance = new MyClass(); console.log(instance.adminMethod()); // Throws error if role is not 'admin'
-
依赖注入:通过类装饰器,可以实现依赖注入的功能。
function Injectable(target: any) { // 这里可以实现依赖注入的逻辑 console.log(`Injectable class: ${target.name}`); } @Injectable class MyService { constructor() {} }
-
属性验证:通过属性装饰器,可以在属性赋值时进行验证。
function validate(target: any, key: string) { let value = target[key]; const getter = () => value; const setter = (newValue: string) => { if (newValue.length > 10) { throw new Error('Value is too long'); } value = newValue; }; Object.defineProperty(target, key, { get: getter, set: setter, enumerable: true, configurable: true, }); } class MyClass { @validate myProperty: string; } const instance = new MyClass(); instance.myProperty = 'Hello'; // Works fine instance.myProperty = 'This is too long'; // Throws error
-
路由绑定:在框架中,装饰器可以用于绑定路由。
function Route(path: string) { return function (target: any, key: string, descriptor: PropertyDescriptor) { // 这里可以实现路由绑定的逻辑 console.log(`Binding route ${path} to method ${key}`); }; } class MyController { @Route('/home') home() { return 'Home Page'; } }
总结
装饰器在 TypeScript 中提供了一种强大的元编程能力,允许开发者在不修改原始代码的情况下,动态地扩展或修改类的行为。它们在框架开发、日志记录、权限控制、依赖注入等场景中非常有用。然而,装饰器目前仍处于实验阶段(Stage 2),因此在生产环境中使用时需要谨慎,并确保 TypeScript 配置中启用了 experimentalDecorators
选项。