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

相关资源

相关推荐
怕浪猫4 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎12344 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea4 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
考虑考虑4 小时前
Java实现hmacsha256加密算法
java·后端·java ee
凤山老林5 小时前
聊聊企业级 API 安全:Spring Boot 落地 OAuth 2.1、mTLS 与接口签名防篡改
spring boot·后端·安全·oauth
林鹿6 小时前
maven属性与groovy变量对照表
后端
烽火戏诸诸诸侯6 小时前
AI 让我的独门小工具焕发第二春
后端·ai编程·vibecoding
狼爷7 小时前
硅谷爆火的FDE是AI新风口,还是高级外包?
后端·全栈
几何心凉7 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen7 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude