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. 保持一致性:在同一个项目中,保持使用方式的一致性

相关资源

相关推荐
WindrunnerMax3 小时前
从零实现富文本编辑器#11-Immutable状态维护与增量渲染
前端·架构·前端框架
不想秃头的程序员3 小时前
Vue3 封装 Axios 实战:从基础到生产级,新手也能秒上手
前端·javascript·面试
爱装代码的小瓶子3 小时前
【C++与Linux基础】进程间通讯方式:匿名管道
android·c++·后端
数研小生3 小时前
亚马逊商品列表API详解
前端·数据库·python·pandas
你听得到113 小时前
我彻底搞懂了 SSE,原来流式响应效果还能这么玩的?(附 JS/Dart 双端实战)
前端·面试·github
不倒翁玩偶3 小时前
npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
前端·npm·node.js
奔跑的web.3 小时前
UniApp 路由导航守
前端·javascript·uni-app
程序员良许3 小时前
嵌入式处理器架构
后端·单片机·嵌入式
EchoEcho3 小时前
记录overflow:hidden和scrollIntoView导致的页面问题
前端·css