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

相关资源

相关推荐
To_OC13 小时前
手写 AI 编程 Agent 的命令执行工具:我被 child_process 坑出来的实战经验
后端·node.js·agent
胡萝卜术13 小时前
从API调用到手写LRU:力扣146「LRU缓存」的哈希表+双向链表终极进化之路
前端·javascript·面试
科技道人13 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
天疆说13 小时前
Zotero Connector 在 Edge 里找不到桌面 Zotero(Linux / Zotero 9.0.6 / Edge 150)
linux·前端·edge
李伟_Li慢慢14 小时前
02-从硬件说起WebGL
前端·three.js
逝水无殇15 小时前
C# 异常处理详解
开发语言·后端·c#
kyriewen15 小时前
看了微软几万人用AI编程的数据——效率涨24%的代价没人提
前端·ai编程·claude
2601_9637713715 小时前
How to Scale Your WordPress Store Traffic in 2026
前端·php·plugin
亿元程序员16 小时前
老板说我的3D箭头游戏用来做试玩太普通了,没人想玩,让我变点花样...
前端
李伟_Li慢慢16 小时前
01-threejs架构原理-课程简介
前端·three.js