Inconsistent behavior between @IsOptional() and PartialType for handling optional properties
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: '[email protected]' } to both endpoints:
// CreateUserDto output:
console.log(createUserDto); // { email: '[email protected]', name: undefined }
// UpdateUserDto output:
console.log(updateUserDto); // { email: '[email protected]' }
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: '[email protected]' }
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.
Set useDefineForClassFields flag in ts config to false. This flag by default initializes class properties to undefined if "they have no initializer".
It seems @nisarg-78 has a solution for this, but ultimately I don't see exactly how this is a problem in class-validator, as class-validator is not creating instances of your classes in Nestjs, it just validates what it is given.
It falls on you to use the correct validation decorators that will work with your class instances. If you could use some new decorators or validation options, feel free to start a discussion about it.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.