TypeScript 如何做装饰器
上班摸鱼时,你有没有过这样的经历:写了几十行代码,突然发现要给某个函数加个“额外功能”——比如自动记录调用时间、报错时发个提醒,要是直接改函数内部代码,不仅乱糟糟,万一改坏了还得重新调试。
其实JavaScript里藏着个好用的小工具,但它自带的能力有限,而TypeScript的装饰器刚好能帮你解决这个麻烦。它就像给你的代码“贴便利贴”,不用拆改原有的功能,就能给类、方法、属性这些代码元素加额外能力,而且TypeScript的装饰器还能做类型检查,比普通JS用着更稳。

先搞懂:装饰器到底是啥?
换个生活化的说法吧。假设你要开一家奶茶店,原本的流程是“做奶茶→打包给顾客”,但你想加个“给杯子印logo”的步骤,总不能把原本的做奶茶流程全改了吧?这时候的“印logo”就是个装饰——不影响原本的核心流程,只是在现有步骤上额外加东西。
TypeScript的装饰器也是这个道理:它是一种特殊的语法,能附加在类、方法、属性、参数这些代码结构上,给它们“加buff”,而且不会改动原有代码的逻辑,后期要去掉也很方便。
要注意的是,用它之前得先开个小开关:在tsconfig.json里把experimentalDecorators设为true,不然TypeScript会不认这个语法哦。
最常用的:类装饰器,给整个类加“统一能力”
如果说奶茶店要给所有杯子印logo,那对应的就是类装饰器——它作用在整个类上。举个例子,你做了个用户信息类User,想给它加个功能:实例创建时自动打个“创建日志”,不用每次手动写。
代码大概是这样的:
`typescript
// 定义一个类装饰器
function logClass(target: any) {
console.log(类 ${target.name} 被创建了);
}
// 把装饰器贴在类上
@logClass
class User {
constructor(public name: string) {}
}
// 实例化类时,就会自动打印“类 User 被创建了”
const user = new User("小明");
`
这里的target就是被装饰的类本身,相当于装饰器拿到了类的“操作权”,能在类创建时加日志、改属性,甚至继承新的能力。
灵活加功能:方法装饰器,给单个方法“贴便利贴”
要是只想给某个方法加功能,比如给用户类的sayHi方法加个“调用时计时”的功能,不用所有方法都加,这时候就用方法装饰器。
还是用奶茶店的例子:要是只给大杯奶茶加“套隔热袋”的步骤,对应的就是方法装饰器,它只作用在你指定的那个方法上。代码大概是:
`typescript
function timer(target: any, methodName: string, descriptor: PropertyDescriptor) {
// 保存原本的方法
const originalMethod = descriptor.value;
// 替换成带计时的新方法
descriptor.value = function (...args: any[]) {
const start = Date.now();
const result = originalMethod.apply(this, args);
const end = Date.now();
console.log(方法 ${methodName} 耗时 ${end - start}ms);
return result;
};
return descriptor;
}
class User {
name: string;
constructor(name: string) {
this.name = name;
}
// 把计时装饰器贴在sayHi方法上
@timer
sayHi() {
// 模拟一点耗时操作,比如查用户信息
for (let i = 0; i < 1000000; i++) {}
return 你好,我是${this.name};
}
}
const user = new User("小红");
user.sayHi(); // 会打印sayHi方法的耗时
`
这里的target是类的原型,methodName是方法名,descriptor存了方法的原始逻辑,我们可以改descriptor.value来替换方法的行为,就像给方法套了层“计时壳”。
别踩的小坑
很多新手容易忘开experimentalDecorators这个配置,导致TypeScript直接报错;另外装饰器的执行顺序要注意:参数装饰器>方法装饰器>属性装饰器>类装饰器,顺序错了可能会出奇怪的bug。
其实TypeScript装饰器就是帮你把“零散的额外功能”从原代码里抽出来,让代码更整洁、好维护。下次给代码加日志、权限校验这些功能时,试试用它,不用再把原代码改得乱糟糟啦。