Декоратор @IsNotEmpty из библиотеки class-validator
предназначен для проверки значения на пустоту. Валидатор отклоняет
значения:
'' — пустая строка;null;undefined.Во всех остальных случаях проверка считается успешной.
Установка:
npm install class-validator class-transformer
Базовая настройка:
import 'reflect-metadata';
В tsconfig.json должны быть включены параметры:
{
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
import { IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsNotEmpty()
username: string;
}
Проверка:
import { validate } from 'class-validator';
const dto = new CreateUserDto();
dto.username = '';
const errors = await validate(dto);
console.log(errors);
Результат:
[
{
property: 'username',
constraints: {
isNotEmpty: 'username should not be empty'
}
}
]
dto.username = '';
Ошибка валидации возникнет.
nulldto.username = null;
Проверка не пройдет.
undefineddto.username = undefined;
Валидация завершится ошибкой.
dto.username = 'admin';
Проверка успешна.
dto.username = ' ';
Важная особенность: @IsNotEmpty считает такую строку
валидной, потому что строка не является пустой технически.
dto.count = 0;
Значение 0 не считается пустым.
falsedto.isActive = false;
Булево значение false проходит проверку.
@IsNotEmpty от @IsDefinedДекоратор @IsDefined проверяет только наличие
значения:
@IsDefined()
name: string;
Он запрещает:
nullundefinedНо разрешает:
''
@IsNotEmpty работает строже и дополнительно запрещает
пустую строку.
@IsNotEmpty
от @IsEmpty@IsNotEmptyТребует, чтобы значение существовало и не было пустым.
@IsNotEmpty()
title: string;
@IsEmptyНаоборот, требует отсутствия значения.
@IsEmpty()
deletedAt: null;
import { IsNotEmpty } from 'class-validator';
export class RegisterDto {
@IsNotEmpty()
login: string;
@IsNotEmpty()
password: string;
@IsNotEmpty()
email: string;
}
@IsNotEmpty редко применяется в одиночку. Обычно он
комбинируется с другими декораторами.
@IsStringimport { IsNotEmpty, IsString } from 'class-validator';
export class CreateCategoryDto {
@IsString()
@IsNotEmpty()
name: string;
}
Проверка выполняется в два этапа:
@Lengthimport { IsNotEmpty, Length } from 'class-validator';
export class CreatePostDto {
@IsNotEmpty()
@Length(10, 200)
title: string;
}
Ограничения:
@IsEmailimport { IsEmail, IsNotEmpty } from 'class-validator';
export class AuthDto {
@IsNotEmpty()
@IsEmail()
email: string;
}
Порядок декораторов визуально важен для читаемости, хотя сама библиотека не всегда строго зависит от него.
Распространенная практика:
@IsString()
@IsNotEmpty()
@Length(3, 20)
username: string;
Сначала указывается тип, затем обязательность, затем дополнительные ограничения.
@IsNotEmpty({
message: 'Имя пользователя обязательно'
})
username: string;
Результат:
{
isNotEmpty: 'Имя пользователя обязательно'
}
@IsNotEmpty({
message: (args) => {
return `Поле ${args.property} не должно быть пустым`;
}
})
title: string;
Декоратор особенно часто применяется в NestJS внутри DTO.
import { IsNotEmpty } from 'class-validator';
export class CreateProductDto {
@IsNotEmpty()
name: string;
@IsNotEmpty()
description: string;
}
import { ValidationPipe } from '@nestjs/common';
app.useGlobalPipes(new ValidationPipe());
После этого входящие HTTP-запросы будут автоматически проверяться.
{
"name": "",
"description": "Телефон"
}
{
"statusCode": 400,
"message": [
"name should not be empty"
],
"error": "Bad Request"
}
skipMissingPropertiesПараметр skipMissingProperties влияет на поведение
валидатора.
validate(dto, {
skipMissingProperties: true
});
Если свойство отсутствует:
{}
то @IsNotEmpty не будет вызван.
Но если свойство присутствует:
{
"name": ""
}
валидация завершится ошибкой.
PartialTypeВ NestJS часто используется:
PartialType(CreateUserDto)
Все поля становятся необязательными.
Однако если поле передано:
{
"name": ""
}
@IsNotEmpty всё равно сработает и вернет ошибку.
@IsNotEmpty()
tags: string[];
Особенность: пустой массив [] считается валидным.
Причина — массив не равен:
nullundefined''Для массивов лучше использовать:
import { ArrayNotEmpty } from 'class-validator';
export class PostDto {
@ArrayNotEmpty()
tags: string[];
}
Теперь:
[]
вызовет ошибку.
@IsNotEmpty()
settings: object;
Пустой объект:
{}
считается валидным.
Для более строгой проверки требуется кастомная логика.
Частая ошибка:
title = ' ';
@IsNotEmpty пропустит значение.
@TransformИспользование class-transformer:
import { Transform } from 'class-transformer';
import { IsNotEmpty } from 'class-validator';
export class CreateArticleDto {
@Transform(({ value }) => value.trim())
@IsNotEmpty()
title: string;
}
Теперь строка:
' '
превратится в:
''
и валидация завершится ошибкой.
import { IsNotEmpty, IsNumber } from 'class-validator';
export class PaymentDto {
@IsNumber()
@IsNotEmpty()
amount: number;
}
Значение:
0
будет валидным.
Если требуется запретить ноль:
import { Min } from 'class-validator';
@Min(1)
amount: number;
import { IsBoolean, IsNotEmpty } from 'class-validator';
export class SettingsDto {
@IsBoolean()
@IsNotEmpty()
enabled: boolean;
}
Значение:
false
проходит валидацию.
import {
IsNotEmpty,
ValidateNested
} from 'class-validator';
import { Type } from 'class-transformer';
class ProfileDto {
@IsNotEmpty()
bio: string;
}
class UserDto {
@ValidateNested()
@Type(() => ProfileDto)
profile: ProfileDto;
}
const dto = new UserDto();
dto.profile = {
bio: ''
};
Результат:
[
{
property: 'profile',
children: [
{
property: 'bio',
constraints: {
isNotEmpty: 'bio should not be empty'
}
}
]
}
]
Использование @ValidateIf:
import {
IsNotEmpty,
ValidateIf
} from 'class-validator';
export class UpdatePasswordDto {
@ValidateIf(o => o.changePassword)
@IsNotEmpty()
newPassword: string;
changePassword: boolean;
}
Поле newPassword проверяется только при:
changePassword = true
import { IsNotEmpty } from 'class-validator';
export class UserDto {
@IsNotEmpty({
groups: ['create']
})
password: string;
}
Проверка:
validate(dto, {
groups: ['create']
});
@IsNotEmpty@IsNotEmpty является синхронным декоратором и не
выполняет асинхронных операций. Он лишь проверяет текущее значение
свойства.
Упрощенная логика валидатора:
value !== '' &&
value !== null &&
value !== undefined
Именно поэтому:
0 проходит проверку;false проходит проверку;[] проходит проверку;{} проходит проверку.Неправильно:
@IsNotEmpty()
age: any;
Лучше:
@IsNumber()
@IsNotEmpty()
age: number;
Ошибка ожидания:
' '
не считается пустой строкой.
Требуется trim().
@IsNotEmpty()
items: string[];
Не гарантирует наличие элементов.
Правильнее:
@ArrayNotEmpty()
items: string[];
import {
IsEmail,
IsNotEmpty,
IsString,
Length
} from 'class-validator';
export class RegisterDto {
@IsString()
@IsNotEmpty({
message: 'Логин обязателен'
})
@Length(3, 20)
login: string;
@IsEmail()
@IsNotEmpty({
message: 'Email обязателен'
})
email: string;
@IsString()
@IsNotEmpty({
message: 'Пароль обязателен'
})
@Length(8, 64)
password: string;
}
@IsNotEmptyДекоратор подходит для:
@IsNotEmpty
недостаточноТребуются дополнительные валидаторы, если необходимо:
| Задача | Валидатор |
|---|---|
| Проверка типа строки | @IsString() |
| Проверка email | @IsEmail() |
| Проверка длины | @Length() |
| Проверка массива | @ArrayNotEmpty() |
| Проверка числа | @IsNumber() |
| Проверка минимального значения | @Min() |
| Проверка объекта | кастомный валидатор |
| Удаление пробелов | @Transform() |