TypeScript - Pick 与 PickType
我目前正在学习 NestJS,为此我正在制作一个关于“任务”的 API。为了保持 DTO 的干净整洁(DRY),我决定创建一个包含 Get 端点返回的所有字段的 TaskDto,并使用 Pick 来创建我 CRUD 中 Post 端点的请求。目前我发现了两种使用 Typescript 来实现的方法:
@Post()
createTask(@Body() request: Pick<TaskDto, 'title' | 'description'>): TaskDto {
return this.taskService.createTask(request);
}
和
@Post()
createTask(@Body() request: CreateTaskDto): TaskDto {
return this.taskService.createTask(request);
}
其中 CreateTaskDto 是:
import { PickType } from '@nestjs/swagger';
import { TaskDto } from './task.dto';
export class CreateTaskDto extends PickType(TaskDto, [
'title',
'description',
]) {}
所以我想知道哪种方式更好。每种方法的“优点”和“缺点”是什么?我对 NestJS 是新手,所以我会很感激你在这个话题上的意见。
附注:我注意到第一种方法在 swagger-ui 和 NestJS 上不起作用。
答案#1
所以这里的 Pick 是一个 Typescript 类型辅助工具,它在 类型 层面上进行更改,这在你最终不需要从装饰器获取元数据反射的时候非常有用。这是因为 Typescript 只会反射类类型,而在使用 tsconfig 中的 emitDecoratorMetadata 选项时不会反射接口或类型层级的类型,而 Nest 广泛使用了这个选项。
PickType 另一方面是一个混入(mixin),一个返回类的函数,它实际上在 Nest 中有三个可以导入的地方:@nestjs/mapped-types 是基础定义,根据传入的类和参数修改 class-validator 和 class-transformer 的元数据,@nestjs/swagger 扩展了 @nestjs/mapped-types 并且 进行 OpenAPI 元数据修改,@nestjs/graphql 扩展了 @nestjs/mapped-types 并且 进行 GraphQL 元数据修改。因为这些都会返回一个类,所以仍然可以使用元数据反射,并且像 ValidationPipe 这样功能仍然可以按预期工作。