在之前的学习中,如果我们想给一个方法增加新功能,通常是直接修改那个方法的源码。但在复杂的企业级开发中,很多功能(比如打印日志、记录执行时间)是通用的,如果每个方法都手动去写一遍,代码会变得非常臃肿。
为了解决这个问题,TypeScript 引入了 “装饰器” 的概念。装饰器就像是一张 “神奇的标签”,我们只要把它贴在类或方法上面,就能在不破坏原有代码结构的前提下,赋予它们额外的能力。
提示: 除了 TypeScript,Python 也有装饰器的概念。
TypeScript 如何开启装饰器?
在学习装饰器之前,有一点大家要清楚:目前 TypeScript 中的装饰器仍然是一项 “实验性功能”。虽然装饰器在 NestJS、Angular 等顶级框架中已经被大规模使用,但 TypeScript 编译器默认是关闭它的。
如果直接写装饰器代码,你会看到满屏的红色报错。因此我们需要在项目的根目录下找到 tsconfig.json 文件,并开启以下配置:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}其中 experimentalDecorators 是开启装饰器语法的开关;而 emitDecoratorMetadata 则是为了配合反射(Reflect)使用的,这两项在开发像 NestJS 那样的底层框架时非常重要。
提示: 关于 tsconfig.json,我们在后续 “TypeScript 配置文件” 一节中会详细介绍。
如果小伙伴们使用的是 TypeScript 5.0 及以上版本,此时会发现就算不开启 experimentalDecorators,直接使用装饰器也不会报错了。这是因为 TypeScript 5.0 已经正式实装了 ECMAScript 的 “标准装饰器”。
那么我们为什么还要开启 “实验性功能” 呢?主要原因有以下 2 点:
- 生态依赖:目前市面上 99% 的顶级框架(如 NestJS、TypeORM、Angular)底层依然严重依赖 “实验性装饰器(Experimental Decorators)” 及其衍生的元数据反射能力(Metadata Reflection)。
- API 差异:标准装饰器和实验性装饰器在底层的参数结构上是不兼容的。
因此,在当前的真实企业级开发环境中,全面开启 experimentalDecorators 依然是绝对的主流做法和行业标准。
TypeScript 装饰器是什么?
在 TypeScript 中,装饰器本质上就是一个普通的函数。我们可以通过 “@” 语法将其附加到类、方法、属性或参数上。
装饰器的核心思想是 “面向切面编程(AOP)”。简单来说,就是把那些与业务逻辑无关的功能(如日志、安全、性能统计)从业务代码中剥离出来,然后像 “切片” 一样横向注入进去。

示例 1:一个最简单的类装饰器
// 定义装饰器函数:参数 target 就是被装饰的类本身
function Sealed(target: Function) {
console.log("[系统]: 正在封闭类 ", target.name);
Object.seal(target); // 封闭类,禁止扩展新属性
}
// 使用装饰器函数
@Sealed
class User {
public name: string = "Jack";
}运行结果如下。
[系统]: 正在封闭类 User分析:
在这个例子中,我们定义了一个名为 “Sealed” 的装饰器函数,然后通过 @Sealed 将其贴在 User 类上方。
当程序加载这个类时,装饰器函数会自动执行。然后你会发现,我们根本没有实例化 User 类,日志就已经打印出来了。这就是装饰器的特点:它在类定义时就会触发执行。
TypeScript 装饰器工厂
在实际业务中,我们往往需要给装饰器传递一些参数。比如,想要指定日志的级别(INFO 或 ERROR)。这时候,我们就需要使用 “装饰器工厂” 了。
所谓的装饰器工厂,其实就是一个 “返回装饰器函数的函数”。
示例 2:实现带参数的日志装饰器
// 定义装饰器工厂
function Log(level: string) {
// 返回真正的装饰器函数
return function(target: Function) {
console.log(`[${level}]: 正在监控类 ${target.name}`);
};
}
@Log("INFO")
class Article {
public title: string = "TypeScript 进阶之路";
}
@Log("WARNING")
class Admin {
public role: string = "SuperAdmin";
}运行结果如下。
[INFO]: 正在监控类 Article
[WARNING]: 正在监控类 Admin分析:
通过这种 “闭包” 写法,我们可以给装饰器注入任意的配置信息。这种方式在开源框架源码中很常见,比如 NestJS 中的 @Controller("/user") 本质上就是一个装饰器工厂,那个 "/user" 字符串就是通过这种方式传进去的。
学习 TypeScript 装饰器,都要学什么?
装饰器是 TypeScript 中最能体现 “架构设计” 思想的功能之一。它让我们学会了如何把 “业务逻辑” 与 “辅助功能” 进行优雅地解耦。
虽然装饰器的语法看起来很魔幻,但小伙伴们只要记住一句话就行:装饰器,就是一个在特定时机被自动触发的函数。
在接下来的几篇中,我们将由浅入深,逐一攻克装饰器的四大领地:
