@IsInt

Декоратор @IsInt из библиотеки class-validator используется для проверки того, что значение свойства является целым числом. Под целым числом понимается числовой тип без дробной части, например 0, 1, -10, 42. Значения 3.14, 2.0 (в некоторых случаях преобразования), строки и другие типы считаются невалидными, если не применены дополнительные преобразования.


Базовое назначение и поведение

Основная задача @IsInt — обеспечить строгую проверку входных данных на уровне DTO (Data Transfer Object). Это особенно важно в приложениях, где данные поступают извне: HTTP-запросы, очереди сообщений, внешние API.

Проверка выполняется следующим образом:

  • значение должно быть типа number
  • значение должно быть конечным числом
  • значение должно не содержать дробной части

Примеры валидных значений:

  • 10
  • 0
  • -25

Примеры невалидных значений:

  • 10.5
  • "10"
  • NaN
  • Infinity

Синтаксис использования

import { IsInt } fr om 'class-validator';

class CreateUserDto {
  @IsInt()
  age: number;
}

В этом примере поле age будет считаться валидным только если оно является целым числом.


Работа в связке с class-transformer

В реальных приложениях входные данные часто приходят в виде строк, даже если они представляют числа. Например, HTTP-запрос:

{
  "age": "25"
}

Без преобразования class-validator получит строку, а не число, и проверка @IsInt не пройдет.

Для решения используется class-transformer:

import { Type } from 'class-transformer';
import { IsInt } from 'class-validator';

class CreateUserDto {
  @Type(() => Number)
  @IsInt()
  age: number;
}

Здесь происходит явное преобразование строки "25" в число 25 перед валидацией.


Валидационные правила и внутренний механизм

@IsInt опирается на строгую проверку типа и значения. Внутренне библиотека проверяет:

  • является ли значение числом (typeof value === "number")
  • не содержит ли оно дробную часть (Number.isInteger(value))

Таким образом, логика эквивалентна:

Number.isInteger(value)

Это означает, что даже числа вида 5.0 в JavaScript уже являются 5, и считаются допустимыми, поскольку фактически не содержат дробной части.


Отличие от @IsNumber

Частая ошибка — использование @IsInt там, где требуется @IsNumber.

  • @IsInt — строго целые числа
  • @IsNumber — любые числа (включая дробные)
import { IsNumber, IsInt } from 'class-validator';

class ExampleDto {
  @IsNumber()
  price: number;

  @IsInt()
  quantity: number;
}

В этом примере:

  • price может быть 10.99
  • quantity должен быть строго 10, 11, 12 и т.д.

Сообщения об ошибках

По умолчанию библиотека возвращает стандартное сообщение об ошибке:

age must be an integer number

Можно переопределить сообщение через ValidationOptions:

import { IsInt, ValidationOptions } from 'class-validator';

class CreateUserDto {
  @IsInt({ message: 'Возраст должен быть целым числом' })
  age: number;
}

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

В экосистеме NestJS @IsInt применяется внутри DTO-классов, которые проходят через ValidationPipe.

import { IsInt } from 'class-validator';

export class UpdateProductDto {
  @IsInt()
  stock: number;
}

Контроллер:

@Post()
create(@Body() dto: UpdateProductDto) {
  return dto;
}

При включённом ValidationPipe:

app.useGlobalPipes(new ValidationPipe({ transform: true }));

входные данные автоматически проверяются и при необходимости преобразуются.


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

Строки

age: "20"

Результат: невалидно, если не используется @Type(() => Number).


Числа с плавающей точкой

age: 20.1

Результат: невалидно.


NaN

age: NaN

Результат: невалидно, поскольку Number.isInteger(NaN) возвращает false.


Infinity

age: Infinity

Результат: невалидно.


Особенности работы валидации

Валидация выполняется после преобразования типов (если оно включено). Это критически важно, поскольку порядок влияет на результат:

  1. class-transformer преобразует данные
  2. class-validator выполняет проверку

Без преобразования большинство входных значений из HTTP окажутся строками и не пройдут @IsInt.


Композиция с другими декораторами

@IsInt часто используется совместно с другими валидаторами для уточнения ограничений.

import { IsInt, Min, Max } from 'class-validator';

class PaginationDto {
  @IsInt()
  @Min(1)
  @Max(100)
  lim it: number;
}

В этом случае:

  • значение должно быть целым числом
  • не меньше 1
  • не больше 100

Типичные ошибки при использовании

Отсутствие преобразования типов

@IsInt()
age: number;

Если приходит "25", проверка провалится.


Ожидание округления

@IsInt не выполняет округление. Значение либо проходит проверку, либо нет.


Использование для строковых чисел

age: "10"

Это не считается числом, даже если строка содержит числовой символ.


Поведение в строгих режимах

При включённой строгой валидации и отключённом преобразовании:

  • любые несоответствия типов приводят к ошибкам
  • отсутствует «неявная магия» приведения типов

Это делает @IsInt особенно полезным для API, где важна предсказуемость входных данных.


Совместимость с массивами и вложенными объектами

@IsInt применяется только к конкретному полю. Для массивов требуется дополнительная комбинация декораторов:

import { IsInt, IsArray } fr om 'class-validator';

class NumbersDto {
  @IsArray()
  @IsInt({ each: true })
  values: number[];
}

Здесь параметр each: true заставляет валидатор проверять каждый элемент массива отдельно.


Практическое применение в архитектуре DTO

@IsInt часто используется для:

  • идентификаторов сущностей (id, userId, productId)
  • количественных значений (count, quantity)
  • параметров пагинации (page, limit)
  • рейтингов и оценок

Типичная структура DTO:

class GetItemsDto {
  @IsInt()
  page: number;

  @IsInt()
  lim it: number;
}

Такая модель позволяет строго контролировать параметры запроса и исключать некорректные данные на раннем этапе обработки.