@IsEmpty

Декоратор @IsEmpty из библиотеки class-validator используется для проверки того, что значение свойства отсутствует. Валидатор считается успешным только в том случае, если поле равно:

  • '' — пустая строка;
  • null;
  • undefined.

Любое другое значение приводит к ошибке валидации.


Назначение @IsEmpty

@IsEmpty применяется в ситуациях, когда свойство объекта:

  • не должно передаваться пользователем;
  • должно оставаться пустым до определённого этапа обработки;
  • заполняется исключительно сервером;
  • запрещено для ручного ввода;
  • резервируется под внутреннюю бизнес-логику.

Типичные примеры:

  • поле role, которое назначается только сервером;
  • системный идентификатор;
  • внутренний статус;
  • дата модерации;
  • служебные метаданные.

Установка библиотеки

npm install class-validator class-transformer

Для поддержки декораторов в TypeScript требуется включить параметры:

{
  "experimentalDecorators": true,
  "emitDecoratorMetadata": true
}

Базовый пример

import { validate } from 'class-validator';
import { IsEmpty } from 'class-validator';

class CreateUserDto {
  @IsEmpty()
  role: string;
}

const dto = new CreateUserDto();

dto.role = 'admin';

validate(dto).then(errors => {
  console.log(errors);
});

Результат:

[
  ValidationError {
    property: 'role',
    constraints: {
      isEmpty: 'role must be empty'
    }
  }
]

Поле содержит значение 'admin', поэтому проверка не проходит.


Успешная валидация

undefined

class CreateUserDto {
  @IsEmpty()
  role?: string;
}
const dto = new CreateUserDto();

Ошибок не будет.


null

class CreateUserDto {
  @IsEmpty()
  role: null;
}

const dto = new CreateUserDto();

dto.role = null;

Проверка успешно пройдёт.


Пустая строка

class CreateUserDto {
  @IsEmpty()
  comment: string;
}

const dto = new CreateUserDto();

dto.comment = '';

Валидация также завершится успешно.


Какие значения считаются непустыми

Следующие значения НЕ проходят проверку @IsEmpty:

'text'
0
false
[]
{}
NaN
true

Пример:

class TestDto {
  @IsEmpty()
  value: any;
}
const dto = new TestDto();

dto.value = false;

Результат:

value must be empty

Даже false считается непустым значением.


Поведение с разными типами данных

Числа

class ProductDto {
  @IsEmpty()
  quantity: number;
}
dto.quantity = 0;

Ошибка:

quantity must be empty

Массивы

class TagsDto {
  @IsEmpty()
  tags: string[];
}
dto.tags = [];

Ошибка валидации всё равно возникнет.

Пустой массив не считается пустым значением для @IsEmpty.


Объекты

class ConfigDto {
  @IsEmpty()
  options: object;
}
dto.options = {};

Проверка завершится ошибкой.


Практическое применение

Запрет передачи системных полей

class RegisterDto {
  username: string;

  password: string;

  @IsEmpty()
  role: string;
}

Пользователь не сможет самостоятельно передать роль:

{
  "username": "alex",
  "password": "123456",
  "role": "admin"
}

Валидация завершится ошибкой.


Защита внутренних статусов

class OrderDto {
  productId: number;

  @IsEmpty()
  status: string;
}

Статус заказа назначается сервером:

order.status = 'pending';

Клиент не должен иметь возможность задавать это поле вручную.


Запрет ручного указания даты

class ArticleDto {
  title: string;

  content: string;

  @IsEmpty()
  publishedAt: Date;
}

Дата публикации может выставляться только после модерации.


Кастомизация сообщения об ошибке

Простое сообщение

class UserDto {
  @IsEmpty({
    message: 'Поле role запрещено для заполнения'
  })
  role: string;
}

Функция генерации сообщения

class UserDto {
  @IsEmpty({
    message: args => {
      return `Свойство ${args.property} должно быть пустым`;
    }
  })
  role: string;
}

Использование вместе с skipMissingProperties

Параметр skipMissingProperties влияет на обработку отсутствующих полей.

Пример:

validate(dto, {
  skipMissingProperties: true
});

Однако @IsEmpty проверяет именно пустоту значения, а не факт существования свойства.


Отличие @IsEmpty от @IsOptional

@IsEmpty

Требует, чтобы поле было пустым.

@IsEmpty()
role: string;

Запрещает наличие значения.


@IsOptional

Разрешает отсутствие поля, но не запрещает значение.

@IsOptional()
role?: string;

Если значение передано — остальные валидаторы будут выполнены.


Отличие @IsEmpty от @IsNotEmpty

@IsEmpty

@IsEmpty()
token: string;

Поле обязано быть пустым.


@IsNotEmpty

@IsNotEmpty()
token: string;

Поле обязано содержать значение.


Комбинирование с другими валидаторами

Пример неправильного сочетания

class TestDto {
  @IsEmpty()
  @IsString()
  value: string;
}

Логическое противоречие:

  • @IsEmpty требует отсутствия значения;
  • @IsString требует строку.

Корректное условное применение

import { ValidateIf, IsEmpty, IsString } from 'class-validator';

class UserDto {
  isAdmin: boolean;

  @ValidateIf(o => !o.isAdmin)
  @IsEmpty()
  adminComment: string;

  @ValidateIf(o => o.isAdmin)
  @IsString()
  adminComment: string;
}

Использование в NestJS

В проектах на NestJS декоратор часто применяется внутри DTO.

import { IsEmpty } from 'class-validator';

export class CreateUserDto {
  username: string;

  @IsEmpty()
  role: string;
}

При использовании ValidationPipe:

app.useGlobalPipes(new ValidationPipe());

любая попытка передать role приведёт к HTTP-ошибке 400 Bad Request.


Проверка скрытых серверных полей

export class PaymentDto {
  amount: number;

  currency: string;

  @IsEmpty()
  internalTransactionId: string;
}

Даже если клиент вручную отправит:

{
  "amount": 100,
  "currency": "USD",
  "internalTransactionId": "ABC123"
}

валидация не позволит принять запрос.


Совместное использование с class-transformer

Часто используется вместе с class-transformer.

import { Expose } from 'class-transformer';
import { IsEmpty } from 'class-validator';

class UserDto {
  @Expose()
  username: string;

  @IsEmpty()
  role: string;
}

Поведение при сериализации

@IsEmpty никак не влияет на:

  • сериализацию;
  • преобразование объектов;
  • удаление полей;
  • скрытие свойств.

Декоратор отвечает исключительно за валидацию.


Типичные ошибки

Ошибка №1: ожидание, что пустой массив считается пустым

@IsEmpty()
tags: string[];
tags = [];

Ошибка всё равно возникнет.


Ошибка №2: сочетание с обязательными валидаторами

@IsEmpty()
@IsNotEmpty()
name: string;

Такой код создаёт невозможное условие.


Ошибка №3: использование для удаления свойства

@IsEmpty()
secret: string;

Декоратор не удаляет поле из объекта.


Внутренний принцип работы

Внутри библиотеки проверка эквивалентна логике:

value === '' ||
value === null ||
value === undefined

Именно эти значения считаются пустыми.


Когда использовать @IsEmpty

Подходящие сценарии:

Сценарий Подходит
Запрет ручного ввода поля Да
Защита серверных данных Да
Скрытые технические поля Да
Контроль внутренних статусов Да
Проверка пустого массива Нет
Проверка пустого объекта Нет

Когда @IsEmpty использовать не стоит

Не рекомендуется применять:

  • для проверки длины строки;
  • для проверки пустых массивов;
  • для проверки объектов без свойств;
  • для удаления полей;
  • как замену @IsOptional.

Для таких задач существуют другие валидаторы:

  • @ArrayNotEmpty
  • @IsOptional
  • @IsNotEmpty
  • @IsDefined

Пример полноценного DTO

import {
  IsEmail,
  IsEmpty,
  IsString,
  MinLength
} from 'class-validator';

export class RegisterDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(6)
  password: string;

  @IsEmpty({
    message: 'Поле role заполняется только сервером'
  })
  role: string;

  @IsEmpty()
  createdAt: Date;
}

Такой DTO:

  • валидирует пользовательские данные;
  • защищает внутренние поля;
  • предотвращает подмену системных значений;
  • разделяет клиентскую и серверную ответственность.