当前位置: 首页 > news >正文

第六部分:第六节 - TypeScript 与 NestJS:打造类型安全的厨房管理流程

NestJS 默认使用 TypeScript,这不仅仅是语法上的变化,更是为整个应用带来了强大的类型安全能力。想象一下,中央厨房里的每一个环节、每一个容器、每一个食材都贴上了精确的标签,并且有严格的规定(类型定义),确保不同区域之间、不同厨师之间传递的数据都是符合预期的。这大大减少了“把油当醋放”、“把盐当糖加”之类的低级错误,在编译阶段就能发现问题。

TypeScript 在 NestJS 中的优势:

  1. 编译时错误检查: 大量潜在的运行时错误(如属性拼写错误、参数类型不匹配)在代码编写或编译阶段就能被发现。
  2. 代码可读性和可维护性: 类型注解本身就是一种优秀的文档,清晰地表明了数据结构和函数签名,方便团队协作和后续维护。
  3. 强大的开发工具支持: VS Code 等编辑器对 TypeScript 有极好的支持,提供了智能代码补全、错误提示、重构等功能,显著提高开发效率。

使用接口 (Interface) 和类 (Class) 定义 DTOs:

DTO (Data Transfer Object) 是一个用于在应用的不同层之间(比如从控制器到服务,或者从服务到外部 API)传输数据的对象。在 NestJS 中,我们通常使用 TypeScript 的接口或类来定义 DTO 的形状,特别是用于描述请求体和响应体的数据结构。这就像为不同环节的订单或菜品定义了标准化的表格或容器。

  • 接口 (Interface): 简单地描述对象的结构。轻量级,只在编译时存在。
  • 类 (Class): 除了描述结构,还可以包含方法,并且在运行时存在(可以用于创建实例,也可以与 NestJS 的 Pipes 进行更复杂的验证集成)。在定义请求体 DTO 时,通常推荐使用类,因为可以结合 class-validator 和 class-transformer 库进行强大的数据验证和转换(这属于更高级的话题,这里先了解概念)。

小例子:为用户模块定义 DTO

创建一个文件 src/users/dto/create-user.dto.ts:

// src/users/dto/create-user.dto.ts
// 使用类定义 DTO,方便后续的数据验证
export class CreateUserDto {name: string; // 必须提供 name 属性,且是 string 类型age: number; // 必须提供 age 属性,且是 number 类型
}

创建一个文件 src/users/dto/update-user.dto.ts:

// src/users/dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types'; // 导入 PartialType// 使用 PartialType 基于 CreateUserDto 创建一个新类型
// PartialType 会让 CreateUserDto 中的所有属性变成可选 (?)
export class UpdateUserDto extends PartialType(CreateUserDto) {// 可以添加其他更新时特有的属性
}

PartialType 是 NestJS 提供的一个 Utility Type,它可以帮助我们方便地基于现有 DTO 创建一个所有属性都变成可选的新 DTO 类型,非常适合用于更新操作的请求体。

修改 src/users/users.controller.tssrc/users/users.service.ts 以使用这些 DTO:

src/users/users.controller.ts (修改):

// src/users/users.controller.ts
import { Controller, Get, Post, Put, Delete, Param, Body, NotFoundException, HttpCode, HttpStatus } from '@nestjs/common';
import { UsersService } from './users.service';
import { ParseIntPipe } from '@nestjs/common';// 导入 DTO
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';@Controller('api/users')
export class UsersController {constructor(private readonly usersService: UsersService) {}@Get()findAll() {return this.usersService.findAll();}@Get(':id')findOne(@Param('id', ParseIntPipe) id: number) {const user = this.usersService.findOne(id);if (!user) {throw new NotFoundException(`找不到 ID 为 ${id} 的用户`);}return user;}@Post()@HttpCode(HttpStatus.CREATED)// 使用 CreateUserDto 作为请求体的类型注解create(@Body() createUserDto: CreateUserDto) {const newUser = this.usersService.create(createUserDto);return newUser; // 返回的用户对象的类型也是明确的 (User 接口)}@Put(':id')// 使用 UpdateUserDto 作为请求体的类型注解update(@Param('id', ParseIntPipe) id: number, @Body() updateUserDto: UpdateUserDto) {const updatedUser = this.usersService.update(id, updateUserDto);if (!updatedUser) {throw new NotFoundException(`找不到 ID 为 ${id} 的用户`);}return updatedUser;}@Delete(':id')@HttpCode(HttpStatus.NO_CONTENT)remove(@Param('id', ParseIntPipe) id: number) {const removed = this.usersService.remove(id);if (!removed) {throw new NotFoundException(`找不到 ID 为 ${id} 的用户,无法删除`);}}
}

src/users/users.service.ts (修改):

// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
// 导入 DTO
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';// 定义一个简单的用户接口
interface User {id: number;name: string;age: number;
}@Injectable()
export class UsersService {private users: User[] = [{ id: 1, name: 'Alice', age: 28 },{ id: 2, name: 'Bob', age: 32 },];findAll(): User[] {return this.users;}findOne(id: number): User | undefined {return this.users.find(user => user.id === id);}// create 方法的参数使用 CreateUserDto 类型create(userData: CreateUserDto): User {const newUser = {id: this.users.length > 0 ? this.users[this.users.length - 1].id + 1 : 1,...userData,};this.users.push(newUser);return newUser;}// update 方法的参数使用 UpdateUserDto (Partial<User>) 类型update(id: number, updateData: UpdateUserDto): User | undefined {const userIndex = this.users.findIndex(user => user.id === id);if (userIndex === -1) {return undefined;}this.users[userIndex] = { ...this.users[userIndex], ...updateData };return this.users[userIndex];}remove(id: number): boolean {const initialLength = this.users.length;this.users = this.users.filter(user => user.id !== id);return this.users.length < initialLength;}
}

现在,你的 NestJS 应用从请求体接收数据、到服务处理数据、再到控制器返回数据,整个流程都有明确的类型定义。这使得代码更加清晰,也更容易通过 TypeScript 编译器发现潜在的类型错误。

小结: NestJS 对 TypeScript 的原生支持是其重要优势。通过为请求/响应数据定义 DTO(使用接口或类),并为控制器和服务的方法参数和返回值添加类型注解,可以实现端到端(从网络请求到业务逻辑)的类型安全。这极大地提高了代码的健壮性和可维护性,就像中央厨房有了严格的流程和清晰的标签,确保了出品质量。

练习:

  1. 在你之前的 my-backend 项目中,为产品模块定义 DTO。创建一个 src/products/dto 目录。
  2. src/products/dto 目录下创建 create-product.dto.tsupdate-product.dto.ts 文件。
  3. create-product.dto.ts 中定义一个类 CreateProductDto,包含 name (string) 和 price (number) 属性。
  4. update-product.dto.ts 中定义一个类 UpdateProductDto,使用 PartialType 基于 CreateProductDto 创建(或者手动定义属性为可选)。
  5. 修改 products.controller.tsproducts.service.ts,在 createupdate 方法中使用 CreateProductDtoUpdateProductDto 作为参数的类型注解。
  6. 确保你的 Service 方法返回值的类型也与你之前定义的接口或类一致(例如,findAll 返回 Product[])。
  7. 运行应用,使用 Postman 等工具测试你的产品 API,观察在发送错误类型的数据时,TypeScript 是否能在编译阶段提供帮助(例如,如果你尝试在代码中将字符串赋给 price 属性)。运行时则依赖于你是否使用了 Pipes 进行运行时验证。
http://www.xdnf.cn/news/592849.html

相关文章:

  • 3356. 零数组变换 II
  • Spring Boot 多租户架构实现:基于上下文自动传递的独立资源隔离方案
  • 为什么mosquitto 禁用了 topic “#“后,无法使用主题中包含%c client_id了?
  • python容器
  • PTA刷题笔记
  • 浏览器原生 Web Crypto API 实现 SHA256 Hash 加密
  • 六:操作系统虚拟内容之内存文件映射
  • DeepSeek的进阶应用场景大全
  • poppler_path 是用于 Python 库如 pdf2image 进行 PDF 转换时
  • 《告别单一智能:神经符号混合系统驱动推理能力的跨界融合》
  • 哈希表和容器中添加元素的方法
  • 什么是CDN(Content Delivery Network,内容分发网络)
  • ubunt配置本地源
  • Linux开发板串口终端会限制命令字符数并且循环覆盖
  • 并发编程 之 TreeMap ConcurrentSkipListMap set queue源码分析
  • 自动化测试报告工具
  • 【八股战神篇】Redis高频面试题
  • AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年5月22日第85弹
  • 数据结构知识点汇总
  • 速卖通关键词搜索API开发指南
  • 简单说一下px和ex 的区别......
  • 测试文章1
  • ATGM336H-6N_GNSS 单频多模定位导航模块
  • IEEE Wireless Communications 2025年1月-4月论文速览
  • 二十一、面向对象底层逻辑-scope作用域接口设计
  • 05算法学习_59. 螺旋矩阵 II
  • 如何测试JWT的安全性:全面防御JSON Web Token的安全漏洞
  • 第34节:迁移学习中的特征提取方法
  • 落石滑坡倒树自然灾害检测数据集VOC+YOLO格式958张3类别
  • Linux 搭建FTP服务器(vsftpd)