typescript装饰器是运行时函数,需配置experimentaldecorators和emitdecoratormetadata;分四类:类、方法、属性、参数装饰器,各具参数与用途;常用装饰器工厂和元数据实现动态行为与声明式校验。

TypeScript 装饰器不是语法糖,而是运行时可执行的函数,它让类和成员具备“自我描述”与“行为注入”的能力。要真正用起来,得先开开关、懂类型、分场景写——不配置就报错,不理解参数就改不了行为,不区分装饰器类型就套错地方。
必须开启编译器支持
装饰器是实验性特性,TypeScript 默认关闭。需在 tsconfig.json 中明确启用:
- experimentalDecorators: true —— 启用 @decorator 语法解析
-
emitDecoratorMetadata: true —— 允许在装饰器中读取参数类型、属性类型等反射信息(依赖
reflect-metadata包)
缺少任一配置,装饰器可能不执行、元数据为空,或编译直接报错。
四类装饰器的参数与典型用途
每种装饰器接收不同参数,对应不同操作粒度:
-
类装饰器:接收一个参数 —— 类的构造函数(
target: Function)。适合修改构造逻辑、添加静态属性、注册全局实例(如单例)、冻结原型链(Object.seal)。 -
方法装饰器:接收三个参数 —— 目标对象(原型或构造函数)、方法名(
propertyKey: string)、属性描述符(descriptor: PropertyDescriptor)。常用于日志、性能监控、权限拦截、缓存包装。 -
属性装饰器:接收两个参数 —— 目标对象、属性名(
propertyKey: string)。不能直接拦截读写(ES6 不支持),但可用于收集元数据(如字段校验规则、序列化标识)、配合Object.defineProperty模拟访问控制。 -
参数装饰器:接收三个参数 —— 目标对象、方法名、参数索引(
index: number)。单独作用有限,通常与方法装饰器配合,用于提取参数类型或绑定上下文(如 NestJS 的@Body()、@Query())。
写一个带参数的装饰器工厂
直接写 @Log 太死板,多数实用场景需要传参(比如日志级别、超时阈值、路由路径)。这时要用“装饰器工厂”:外层函数收参数,内层函数才是真正的装饰器。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
例如一个带阈值的方法耗时监控装饰器:
function LogDuration(threshold = 100) {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
const start = performance.now();
const result = original.apply(this, args);
const elapsed = performance.now() - start;
if (elapsed > threshold) {
console.warn(`⚠ ${propertyKey} took ${elapsed.toFixed(1)}ms`);
}
return result;
};
};
}
<p>class ApiClient {
@LogDuration(50) // 阈值设为 50ms
fetchData() {
return new Promise(r => setTimeout(r, 60));
}
}</p>
调用 fetchData() 就会触发警告,而其他方法不受影响。
属性装饰器如何配合元数据使用
单纯标记属性意义不大,但结合 Reflect.defineMetadata 和 Reflect.getMetadata,就能实现声明式校验或序列化策略:
- 先安装:
npm install reflect-metadata,并在入口文件顶部加import 'reflect-metadata'; - 定义装饰器记录类型和校验规则:
function Validate(required: boolean = false, maxLength?: number) {
return function (target: any, propertyKey: string) {
Reflect.defineMetadata('validation', { required, maxLength }, target, propertyKey);
};
}
<p>class User {
@Validate(true, 20)
name!: string;
}</p>
后续可通过 Reflect.getMetadata('validation', User.prototype, 'name') 拿到规则,供校验器统一处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










