装饰器是特殊的注解,它们允许通过额外的元信息或替代实现来改变类、属性、方法或参数的行为。
通常用于依赖注入、日志记录、验证、缓存或为像Angular之类的框架声明元数据。
简单方法装饰器示例:
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Call: ${propertyKey}(${JSON.stringify(args)})`); return original.apply(this, args); }; } class Example { @Log doSomething(a: number, b: number) { return a + b; } }
陷阱:
experimentalDecorators时才有效。问题: "是否可以对装饰器的参数进行类型化,以确保应用它的方法的类型?"
答案: 在大多数情况下,由于元编程的动态特性,装饰器应用时的类型化是不可能的。然而,通过泛型和额外的运行时检查可以添加验证,但TypeScript编译器在声明结构时无法提供保证。
示例:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // 编译器并不保证该方法返回number
故事
在一个有大量服务装饰器的项目中,忘记了应用顺序:属性装饰器在所有参数之前被应用,这导致Inject元数据丢失,并且在运行时无法解析依赖关系。
故事
开发者决定将装饰器应用于普通函数,而不是类的方法,并对编译错误和缺乏运行时效果感到惊讶。在TypeScript规格中,装饰器仅适用于类及其成员。
故事
在更新TypeScript版本和实验性设置后,自定义DI容器中的装饰器机制完全崩溃:新版本显然需要显式支持Reflect-metadata,否则所有元信息都会丢失。