是否可以在 NestJs 中为 DTO 进行继承?

Posted

技术标签:

【中文标题】是否可以在 NestJs 中为 DTO 进行继承?【英文标题】:Is it possible to do inheritance for DTOs in NestJs? 【发布时间】:2020-05-30 03:38:59 【问题描述】:

我有一个 NestJs Get 控制器,用于搜索员工列表。

@Controller('employee')
export class EmployeeController 
    private logger = new Logger('EmployeeController');
    constructor(private employeeService:EmployeeService)

    @Get()
    @UsePipes(new ValidationPipe( transform: true ))
    getEmployees(
        @Query() filter:GetEmployeesFilterDto
    ):Promise<Employee[]>
        console.log(JSON.stringify(filter), filter.batch);
        return this.employeeService.getEmployees(filter);
    

为了支持分页,该方法接受一个过滤器DTO来接受批量大小和页码等参数。看到这将如何成为其他 DTO 类的通用参数,我想到了创建一个基本过滤器 DTO:

export class BaseQueryFilterDto

    @IsOptional()
    @IsInt()
    @UsePipes(ParseIntPipe)
    batch:number;

    @IsOptional()
    @IsInt()
    @UsePipes(ParseIntPipe)
    skip:number;


然后为 GetEmployeesFilterDto 继承这个 DTO:

export class GetEmployeesFilterDto extends BaseQueryFilterDto
    @IsOptional()
    @IsNotEmpty()
    search:string;

    @IsOptional()
    primarySupervisorId:string;


运行以下请求http://localhost:3000/employee?batch=30会抛出以下异常:

[Nest] 27920   - 02/14/2020, 6:29:54 PM   [ExceptionsHandler] Cannot assign to read only property 'batch' of object '#<GetEmployeesFilterDto>' +606974ms
TypeError: Cannot assign to read only property 'batch' of object '#<GetEmployeesFilterDto>'
    at _loop_1 (C:\ng-proj\nestjs-tutorial\node_modules\class-transformer\TransformOperationExecutor.js:242:47)
    at TransformOperationExecutor.transform (C:\ng-proj\nestjs-tutorial\node_modules\class-transformer\TransformOperationExecutor.js:260:17)
    at ClassTransformer.plainToClass (C:\ng-proj\nestjs-tutorial\node_modules\class-transformer\ClassTransformer.js:17:25)    at Object.plainToClass (C:\ng-proj\nestjs-tutorial\node_modules\class-transformer\index.js:20:29)
    at ValidationPipe.transform (C:\ng-proj\nestjs-tutorial\node_modules\@nestjs\common\pipes\validation.pipe.js:55:41)
    at transforms.reduce (C:\ng-proj\nestjs-tutorial\node_modules\@nestjs\core\pipes\pipes-consumer.js:15:33)
    at process._tickCallback (internal/process/next_tick.js:68:7)

但是,当我像这样将所有属性从超类移动到 GetEmployeesFilterDto 时:

export class GetEmployeesFilterDto extends BaseQueryFilterDto
    @IsOptional()
    @IsNotEmpty()
    search:string;

    @IsOptional()
    primarySupervisorId:string;

    //Moved from BaseQueryFilterDto
    @IsOptional()
    @IsInt()
    @UsePipes(ParseIntPipe)
    batch:number;

    @IsOptional()
    @IsInt()
    @UsePipes(ParseIntPipe)
    skip:number;


请求成功运行。 我在这里遗漏了什么,或者我不能在 NestJs 中实现对控制器 DTO 的继承吗?

【问题讨论】:

这看起来像是来自堆栈跟踪的class-transformer 问题。您可以尝试联系class-transformer 寻求帮助吗? 为什么你要定义的属性有@UsePipes()?该装饰器仅适用于控制器、控制器方法和控制器方法参数 @JayMcDoniel,如果没有 ParseIntPipe,IsInt 验证将失败,因为来自查询字符串的所有值都是字符串。也许这是对 DTO 属性进行 parseInt 的错误方法。抱歉,我对 NestJs 很陌生 @vinnyo 为什么不使用来自class-trasnformer@Type() 转换作为验证过程的一部分,这样在验证后它也将被解析并且您不会在a 中使用@UsePipe()奇怪的地方? @JayMcDoniel,最初,我尝试使用@Type(),但遇到了验证错误。但我现在意识到我不应该用@Type() 添加@IsInt() 验证装饰器。将用答案更新我的帖子。非常感谢! 【参考方案1】:

感谢@JayMcDoniel 指出我不应该在属性上使用@UsePipes()

这是适合我的解决方案。

export class BaseQueryFilterDto

    @IsOptional()
    @Type(() => Number)
    batch:number;

    @IsOptional()
    @Type(() => Number)
    skip:number;


【讨论】:

以上是关于是否可以在 NestJs 中为 DTO 进行继承?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 NestJs 框架中使用 postgres 和 sequelize 正确定义 DTO 对象

如何在 NestJS 中编写嵌套 DTO

NestJs:为啥我们不使用 DTO 来替换所有接口?

NestJs - DTO 和实体

如何在 Nestjs 上使用具有多个 dto 的一条路由?

NestJS 与猫鼬模式、接口和 dto 方法问题