Description
Description
In NestJS, there is an inconsistency in how optional properties are handled between DTOs using @IsOptional()
decorator and DTOs using PartialType
. When using @IsOptional()
, properties that are not provided in the request are set to undefined
, while PartialType
completely omits these properties. This creates confusing behavior when working with both types of DTOs.
Minimal code-snippet showcasing the problem
import { IsEmail, IsOptional, IsString } from 'class-validator';
import { PartialType } from '@nestjs/swagger';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@IsOptional()
name: string;
}
export class UpdateUserDto extends PartialType(CreateUserDto) {}
// When sending request { email: 'test@example.com' } to both endpoints:
// CreateUserDto output:
console.log(createUserDto); // { email: 'test@example.com', name: undefined }
// UpdateUserDto output:
console.log(updateUserDto); // { email: 'test@example.com' }
Expected behavior
Both @IsOptional()
and PartialType
should handle optional properties consistently. When a property is not provided in the request, it should be completely omitted rather than being set to undefined
. The behavior should be consistent across both approaches:
// Expected output for both DTOs:
// { email: 'test@example.com' }
Actual behavior
Currently, there are two different behaviors:
- With
@IsOptional()
:
// CreateUserDto output:
{ email: '[email protected]', name: undefined }
- With
PartialType
:
// UpdateUserDto output:
{ email: '[email protected]' }
This inconsistency can lead to confusion when developers are working with both types of DTOs in the same application. It's particularly problematic when the same property is handled differently depending on whether it's in a create or update operation.