TypeScript 类型工具与 NestJS Mapped Types

概述

在 NestJS 开发中,我们经常需要创建 DTO(Data Transfer Object)类。NestJS 提供了 @nestjs/mapped-types 包来帮助我们基于现有类创建新的 DTO 类,同时保留装饰器和验证元数据

TypeScript 内置类型工具 vs NestJS Mapped Types

1. PartialType vs Partial

TypeScript 内置 Partial

typescript 复制代码
type Partial<T> = {
  [P in keyof T]?: T[P];
};

// 使用示例
interface User {
  name: string;
  age: number;
}

type PartialUser = Partial<User>;
// 结果:{ name?: string; age?: number; }

特点:

  • 仅用于类型检查,编译后不存在
  • 无法保留装饰器和验证元数据
  • 不能用于 class-validator

NestJS PartialType

typescript 复制代码
import { PartialType } from '@nestjs/mapped-types';

class CreateUserDto {
  @IsString()
  name: string;

  @IsNumber()
  age: number;
}

class UpdateUserDto extends PartialType(CreateUserDto) {}
// 结果:一个类,保留了所有装饰器和验证元数据

特点:

  • 运行时存在,是一个真正的类
  • 保留装饰器和验证元数据
  • 可用于 class-validator 和 NestJS DI

2. PickType vs Pick

TypeScript 内置 Pick

typescript 复制代码
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

// 使用示例
type UserName = Pick<User, 'name'>;
// 结果:{ name: string; }

NestJS PickType

typescript 复制代码
import { PickType } from '@nestjs/mapped-types';

class UserNameDto extends PickType(CreateUserDto, ['name'] as const) {}
// 结果:一个类,保留了 name 字段的装饰器

3. OmitType vs Omit

TypeScript 内置 Omit

typescript 复制代码
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

// 使用示例
type UserWithoutAge = Omit<User, 'age'>;
// 结果:{ name: string; }

NestJS OmitType

typescript 复制代码
import { OmitType } from '@nestjs/mapped-types';

class UserWithoutAgeDto extends OmitType(CreateUserDto, ['age'] as const) {}
// 结果:一个类,保留了剩余字段的装饰器

关键区别对比

特性 TypeScript 内置类型 NestJS mapped-types
类型 类型别名(Type Alias) 类(Class)
运行时 不存在(编译后消失) 存在(可在运行时使用)
装饰器 无法保留 保留装饰器和验证元数据
验证 无法用于 class-validator 可用于 class-validator
依赖注入 无法用于 DI 可用于 NestJS DI

使用场景

TypeScript 内置类型(适合纯类型操作)

typescript 复制代码
// 仅用于类型检查,不涉及运行时
function updateUser(id: string, data: Partial<User>) {
  // ...
}

NestJS mapped-types(适合 DTO 和验证)

typescript 复制代码
import { Controller, Post, Patch, Body } from '@nestjs/common';
import { PartialType } from '@nestjs/mapped-types';

@Controller('users')
export class UserController {
  @Post()
  create(@Body() dto: CreateUserDto) {
    // class-validator 会自动验证
  }

  @Patch(':id')
  update(@Body() dto: UpdateUserDto) {
    // UpdateUserDto 继承了 CreateUserDto 的所有验证规则
  }
}

最佳实践

  1. DTO 类使用 mapped-types :当需要创建可验证的 DTO 类时,使用 @nestjs/mapped-types
  2. 纯类型操作使用内置类型:当只需要类型层面的操作时,使用 TypeScript 内置类型
  3. 保持一致性:在同一个项目中,保持使用方式的一致性

相关资源

相关推荐
云技纵横几秒前
Vue无限滚动实战——从原理到企业级优化方案
前端
细心细心再细心2 分钟前
响应式记录
前端·vue.js
s***P9823 分钟前
Spring Boot实时推送技术详解:三个经典案例
spring boot·后端·状态模式
用户69371750013843 分钟前
24.Kotlin 继承:调用超类实现 (super)
android·后端·kotlin
java干货5 分钟前
优雅停机!Spring Boot 应用如何使用 Hook 线程完成“身后事”?
java·spring boot·后端
鹿里噜哩6 分钟前
Spring Authorization Server 打造认证中心(三)自定义登录页
后端·架构
干就完了19 分钟前
关于git的操作命令(一篇盖全),可不用,但不可不知!
前端·javascript
之恒君9 分钟前
JavaScript 垃圾回收机制详解
前端·javascript
是你的小橘呀10 分钟前
像前任一样捉摸不定的异步逻辑,一文让你彻底看透——JS 事件循环
前端·javascript·面试
云技纵横11 分钟前
基于Redis键过期实现订单超时自动关闭:一套优雅的事件驱动方案
后端