Целые и дробные числа

В библиотеке Joi работа с числами строится вокруг базового типа number(), который охватывает как целые, так и дробные значения. Поведение схемы определяется набором цепочных методов, позволяющих уточнять допустимые диапазоны, точность и дополнительные ограничения.

Базовая схема number()

Основой для любой числовой валидации служит Joi.number():

const schema = Joi.number();

Такое определение допускает любые числовые значения, включая целые и дробные. На уровне JavaScript значения проверяются через typeof value === 'number', при этом NaN по умолчанию считается недопустимым.

Типичная схема расширяется ограничениями:

const schema = Joi.number().min(0).max(100);

Здесь задаётся диапазон допустимых значений от 0 до 100 включительно.


Целые числа: integer()

Метод integer() ограничивает входные данные только целыми числами:

const schema = Joi.number().integer();

Допустимыми считаются:

  • 1
  • 0
  • -10

Недопустимыми:

  • 1.5
  • 0.01
  • -3.14

Внутренне проверка основывается на делении числа без остатка. Любое значение с дробной частью отклоняется.

Комбинирование с диапазонами часто используется для идентификаторов и счётчиков:

const schema = Joi.number().integer().min(1);

Такой вариант часто применяется для ID, где отрицательные значения и ноль недопустимы.


Дробные числа и точность

Joi не выделяет отдельного типа для float, однако поддерживает работу с дробными значениями через precision().

const schema = Joi.number().precision(2);

Этот метод ограничивает количество знаков после запятой. Например:

  • 1.23 — допустимо
  • 1.234 — отклоняется
  • 10.5 — допустимо (воспринимается как 10.50)

Важно учитывать, что проверка точности происходит после преобразования числа в стандарт IEEE 754, поэтому возможны особенности с представлением дробей:

0.1 + 0.2 // 0.30000000000000004

Схема с precision() будет оценивать фактическое представление числа, а не математическую абстракцию.


Ограничения min и max

Ограничение диапазона значений задаётся методами min() и max():

const schema = Joi.number().min(10).max(20);

Поведение строгое:

  • значение меньше минимума отклоняется
  • значение больше максимума отклоняется

Комбинация с integer() позволяет формировать строгие диапазоны для счётчиков, страниц, индексов:

const schema = Joi.number().integer().min(0).max(1000);

Кратность значений: multiple()

Метод multiple() проверяет, кратно ли число заданному значению:

const schema = Joi.number().multiple(5);

Допустимые значения:

  • 0
  • 5
  • 10
  • 15

Недопустимые:

  • 3
  • 7
  • 12

Механика основана на остатке от деления. Для дробных чисел поведение зависит от точности представления, поэтому в прикладных сценариях кратность чаще применяется к целым числам.


Приведение типов и coerce

По умолчанию Joi может преобразовывать строки в числа при включённой опции convert:

const schema = Joi.number();
schema.validate("42");

Строка "42" будет приведена к числу 42.

Однако поведение становится менее предсказуемым при некорректных значениях:

  • "42abc" → ошибка
  • "" → ошибка
  • " 42 " → допустимо (после trim и parse)

Явное управление преобразованием:

const schema = Joi.number().strict();

В строгом режиме любые нечисловые типы отклоняются без попыток приведения.


Валидация NaN и Infinity

Числовая модель JavaScript включает специальные значения NaN, Infinity, -Infinity. В Joi они по умолчанию считаются недопустимыми:

Joi.number().validate(NaN);       // ошибка
Joi.number().validate(Infinity);  // ошибка

Для изменения поведения используется:

const schema = Joi.number().allow('Infinity');

Но такие случаи встречаются редко и обычно требуют явной бизнес-логики.


Работа с отрицательными числами

Отрицательные значения регулируются теми же ограничениями:

const schema = Joi.number().min(-100).max(-1);

При отсутствии min() отрицательные числа допустимы по умолчанию:

Joi.number().validate(-5); // допустимо

Сочетание integer и precision

Одновременное использование integer() и precision() не имеет практического смысла, так как целое число не допускает дробной части:

Joi.number().integer().precision(2)

В подобных случаях precision() игнорируется логически, хотя формально может присутствовать в цепочке вызовов.


Проверка чисел в строковом виде

В реальных API часто встречаются числовые значения в виде строк. Joi обрабатывает их при стандартной конфигурации:

const schema = Joi.number();
schema.validate("100");

Преобразование возможно, если строка строго соответствует числовому формату.

Для полного контроля используется:

Joi.number().strict()

Практические комбинации схем

ID сущностей

const idSchema = Joi.number().integer().min(1).required();

Цена товара

const priceSchema = Joi.number().precision(2).min(0);

Пагинация

const pageSchema = Joi.number().integer().min(0);
const limitSchema = Joi.number().integer().min(1).max(100);

Процентные значения

const percentSchema = Joi.number().min(0).max(100);

Поведение при ошибках

Ошибки в числовой валидации формируются с указанием типа нарушения:

  • number.base — значение не является числом
  • number.min — меньше допустимого минимума
  • number.max — превышает максимум
  • number.integer — не является целым числом
  • number.precision — превышена точность
  • number.multiple — не кратно заданному значению

Структура ошибок позволяет точно определять причину отклонения без дополнительной обработки входных данных.