如何在NestJS DTO可选属性中避免Null值?
Great question! The problem with using @IsOptional() alone is that it skips validation for both undefined and null values—when you want optional fields to either be omitted entirely or hold a valid non-null value, this isn't ideal.
Your temporary @ValidateIf() workaround gets the job done, but I totally get wanting a cleaner, more concise solution. Here are a couple of approaches to achieve exactly what you're looking for:
1. Combine @IsOptional() with @IsNotNull()
You mentioned wanting something like @IsNotNull()—turns out you can pair it directly with @IsOptional() to hit your requirement perfectly. This combo means the field is optional (can be left out or set to undefined), but if it's provided, it can't be null:
@ApiProperty({ type: String, format: 'string', required: false, // Marks the field as optional in API docs }) @IsOptional() @IsString() @IsNotNull() readonly name?: string;
How this works: @IsOptional() tells the validator to skip checks if the value is undefined, but if the field exists (even as null), @IsNotNull() will reject the null value, and @IsString() ensures it's a valid string when present.
2. Build a Reusable Custom Decorator
If you find yourself repeating this pattern across multiple DTOs, creating a custom decorator will give you that clean, single-annotation experience you're hoping for. Here's how to set it up:
First, create the decorator file (e.g., custom-validators.ts):
import { applyDecorators } from '@nestjs/common'; import { IsOptional, IsNotNull, ValidationOptions } from 'class-validator'; export function IsOptionalButNotNull(validationOptions?: ValidationOptions) { return applyDecorators( IsOptional(validationOptions), IsNotNull(validationOptions), ); }
Then use it in your DTO like this:
@ApiProperty({ type: String, format: 'string', required: false, }) @IsOptionalButNotNull() @IsString() readonly name?: string;
This wraps the combined logic into a single, readable decorator that behaves just like the concise solution you wanted.
Quick Note on Your Temporary Workaround
Just to confirm, your existing @ValidateIf((o) => o.name !== undefined) approach works because it only runs the @IsString() validation when the field is present (not undefined). If the field is set to null, the validation still triggers and rejects it since null isn't a string. The methods above achieve the same result but with less boilerplate.
内容的提问来源于stack exchange,提问作者Matteo

