HogoZhang
2025-12-05·503 字·2 分钟阅读·
#nestjs#nodejs

NestJS 认识装饰器(Decorator)

从 TypeScript 装饰器基础出发,梳理 NestJS 中类、方法、参数装饰器的典型用法,并通过示例说明其在路由声明、依赖注入和参数提取中的作用。


在 NestJS 中,装饰器(Decorator) 是其核心特性的基础,理解装饰器是顺畅使用 NestJS 的前提。

📌 什么是装饰器?

装饰器是 TypeScript 提供的一种特殊声明,本质上是一个 函数,它可以附加到类、方法、属性或参数上,在不修改原始代码结构的情况下,以声明式的方式注入元数据或增强行为。

语法:使用 @ 符号 + 函数名,写在目标项的上方。

@Controller('users')   // 装饰器
export class UserController {}

🧠 TypeScript 装饰器类型

NestJS 主要用到以下四种装饰器:

类型作用目标示例
类装饰器类构造函数@Controller(), @Injectable(), @Module()
方法装饰器实例方法@Get(), @Post(), @UseGuards()
参数装饰器方法参数@Req(), @Res(), @Body(), @Param(), @Query()
属性装饰器类的属性较少直接使用(常用于自定义元数据)

🏗️ NestJS 中装饰器的作用

NestJS 大量依赖装饰器来构建应用结构,实现了 声明式编程 与 依赖注入:

  • 定义路由:@Get(), @Post() 等告诉 HTTP 服务器,具体方法应处理哪个路径的请求。
  • 标记可注入类:@Injectable() 让类能被 Nest IoC 容器管理。
  • 组装模块:@Module() 将控制器、服务、导入导出等组合成模块。
  • 提取请求数据:@Body(), @Param(), @Query() 直接从 request 对象中获取对应部分。
  • 附加元数据:例如 @SetMetadata() 可为方法/类设置自定义元数据,供守卫或拦截器读取。

✏️ 简单示例

@Controller('products')          // 类装饰器:基路径 /products
export class ProductController {
  constructor(private productService: ProductService) {} // 依赖注入

  @Get(':id')                    // 方法装饰器:GET /products/123
  findOne(@Param('id') id: string) {  // 参数装饰器:提取 id
    return this.productService.findById(id);
  }

  @Post()                        // 方法装饰器:POST /products
  create(@Body() createDto: CreateProductDto) { // 参数装饰器:提取请求体
    // ...
  }
}

🔧 如何自定义装饰器?

NestJS 提供 createParamDecorator 工厂函数,可以创建自己的参数装饰器:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;  // 假设身份验证后 user 被挂载到 request
  }
);

// 在控制器中使用
@Get('profile')
getProfile(@User() user) {   // 直接注入当前用户对象
  console.log(user);
}

💎 总结

  • 装饰器 = 给类/方法/参数打标签的函数。
  • NestJS 利用装饰器实现 声明式路由、依赖注入、数据提取,让代码更简洁优雅。
  • 前置知识:需要熟悉 TypeScript 中的装饰器概念(虽然 TS 默认开启 experimentalDecorators)。
  • 掌握内置装饰器的用法后,可以轻松实现自定义装饰器,大幅提升代码复用性。

如果你对某一类装饰器的具体实现原理感兴趣,我可以进一步展开。