class-validator
class-validator copied to clipboard
feat: IsOptional allow empty strings
I would like to extend the decorator "IsOptional" for my validation. I would like empty strings like ""
to be valid as well. I started with this, but this seems to be the wrong approach:
export function IsOptionalWithEmptyString(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: "isOptionalWithEmptyString",
target: object.constructor,
propertyName: propertyName,
constraints: [function (object, value) {
return object[propertyName] !== null && object[propertyName] !== undefined && object[propertyName] !== "";
}],
options: validationOptions,
validator: ?
});
};
}
How could I implement this? Thank you for your work.
Duplicate of #232?
Thanks for your answer :smiley: , but I don't think this is a duplicate, because #232 is more about a discussion about whether "IsOptional" should also allow empty strings. I think it's ok that "IsOptional" doesn't implement empty strings, but I'd like to implement "IsOptionalWithEmptyString". Or more generally, how can I develop a decorator that disables the following decorators due to a condition?
Any update ?
None of the code bellow is working, I need to allow an empty string or an url:
@IsDefined()
@ValidateIf(e => e !== '') // expected to allow empty string by skipping @IsUrl
@IsUrl()
readonly externalLink: string = '';
@IsDefined()
@ValidateIf(e => e === '') // allow everything ?
@IsUrl()
readonly externalLink: string = '';
https://github.com/typestack/class-validator#conditional-validation
externalLink === ''
should be valid
externalLink === null
should be invalid
externalLink === undefined
should be invalid
externalLink === 'https://github.com/typestack/class-validator/issues/326'
should be valid
I have found a solution for this, you can create a new decorator wrapping ValidateIf
like as follows.
import { ValidationOptions, ValidateIf } from 'class-validator';
export function IsOptional(validationOptions?: ValidationOptions) {
return ValidateIf((obj, value) => {
return value !== null && value !== undefined && value !== '';
}, validationOptions);
}
@ambroiseRabier try this out
@IsUrl()
@ValidateIf(e => e.externalLink !== '') // check only when blank string not found
readonly externalLink: string = '';
Because in @ValidateIf first parameter is an object containing the all property of current class not the property it self.
@NoNameProvided Can we add option to IsOptional to allow empty string?
For example, To allow empty string to pass.
@IsString()
@IsOptional(null, { allowEmptyString: false })
name: string;
What do you think?
For those who are looking for a clean approach, you could use the combination of @IsOptional
with @IsNotEmpty()
:
@IsNotEmpty()
@IsString()
@IsOptional()
name: string;
As the decorators are applied in the reverse order @A @B target => @A(@B(target))
, first, we check if there is some value, then if it is a string, and then that the string is not empty.
Here's my workaround for optional strings:
export class Customer {
...
@ValidateIf((customer) => customer.displayName !== '')
@IsString()
@IsOptional()
displayName?: string;
...
}
This validation accepts empty strings ''
.
In case someone is searching for a way to remove properties with empty strings.
You could combine IsOptional
with Transform
from class-transformer
:
@IsUrl()
@IsOptional()
@Transform((params) => (params.value?.length > 0 ? params.value : undefined))
displayName?: string;
I ended up adding the @Transform following @elovin 's suggestion. Works like a charm but it doesn't look clean :(
@Transform((field) => (!field.value || /^\s*$/.test(field.value)? undefined: field.value))
In our Nest app we just have our own implementation of the IsOptional
decorator:
import { ValidateIf, ValidationOptions } from 'class-validator'
export function IsOptional(validationOptions?: ValidationOptions) {
return ValidateIf((obj, value) => {
return value !== null && value !== undefined && value !== ''
}, validationOptions)
}
But you have to watch out when autocompleting it during use, so that it imports the custom one and not the default IsOptional
.