TypeScript请求响应DTO复用及MongoDB通用字段继承方案咨询
解决方案
一、嵌套DTO类型复用(解决子字段不包含额外字段的问题)
你可以把上层DTO改造为泛型类,通过传入泛型参数动态指定嵌套子属性的类型,既复用结构又不用重复写代码:
// 先定义泛型版本的属性父DTO export class AttributeDto<T = CreateSingleAttributeRequestDto> { readonly attributes?: { readonly cou?: T; readonly sgc?: T; // 其余6个属性同理定义一次即可 } } // 请求DTO直接用默认泛型参数即可 export class CreateAttributeRequestDto extends AttributeDto {} // 响应DTO传入响应版的子属性类型,再额外加自己的字段就行 export class FetchAttributeResponseDto extends AttributeDto<FetchSingleAttributeResponseDto> { @ApiProperty({ example: 98, description: 'GENERATED. Sum of all values of the 8 attributes', format: 'integer', }) @IsInt() readonly total?: number; }
所有attributes下的子字段结构只需要定义一次,请求和响应场景分别传对应子类型即可,完全符合DRY原则,Swagger的装饰器也能正常识别生成文档。
二、MongoDB公共字段复用(解决TypeScript多继承限制问题)
TypeScript虽然不支持原生多继承,但可以通过NestJS生态的标准工具实现多基类合并,首先抽离MongoDB公共字段为独立基础类:
// 抽离MongoDB公共字段基类 export class MongoBaseDto { @ApiProperty({ example: '60d21b4667d0d8992e610c85', description: '文档唯一ID' }) @IsString() readonly _id: string; @ApiProperty({ example: 0, description: '文档版本号' }) @IsInt() readonly __v: number; @ApiProperty({ example: '2024-01-01T00:00:00.000Z', description: '创建时间' }) @IsDate() readonly createdAt: Date; @ApiProperty({ example: '2024-01-01T00:00:00.000Z', description: '更新时间' }) @IsDate() readonly updatedAt: Date; }
使用@nestjs/mapped-types包提供的IntersectionType工具类即可直接合并多个DTO类,天然支持Swagger和class-validator装饰器识别:
import { IntersectionType } from '@nestjs/mapped-types'; // 直接合并业务响应DTO和Mongo公共字段DTO,一行代码搞定 export class FetchAttributeResponseDto extends IntersectionType( AttributeDto<FetchSingleAttributeResponseDto>, MongoBaseDto ) { @ApiProperty({ example: 98, description: 'GENERATED. Sum of all values of the 8 attributes', format: 'integer', }) @IsInt() readonly total?: number; }
如果不想额外引入依赖,也可以自己实现通用Mixin合并函数来合并多个基类的属性和装饰器。
内容的提问来源于stack exchange,提问作者Nivia
相关产品推荐
相关产品推荐

