class-validator icon indicating copy to clipboard operation
class-validator copied to clipboard

Inconsistent behavior between @IsOptional() and PartialType for handling optional properties

Open microCloudCode opened this issue 7 months ago • 1 comments

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:

  1. With @IsOptional():
// CreateUserDto output:
{ email: '[email protected]', name: undefined }
  1. 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.

microCloudCode avatar May 13 '25 12:05 microCloudCode

Set useDefineForClassFields flag in ts config to false. This flag by default initializes class properties to undefined if "they have no initializer".

nisarg-78 avatar May 13 '25 16:05 nisarg-78

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.

braaar avatar Jun 30 '25 10:06 braaar

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.

github-actions[bot] avatar Jul 31 '25 00:07 github-actions[bot]