Positive, negative, integer

Валидация числовых значений в схемах Yup опирается на цепочку методов, которые уточняют допустимые свойства числа. При использовании YupResolver эти правила становятся частью общей схемы валидации, а результат автоматически интегрируется в механизмы обработки форм, например в связке с React Hook Form.

Числовые ограничения positive, negative и integer относятся к базовому набору предикатов, определяющих допустимый диапазон и форму числа. Они применяются после базового определения типа number() и могут комбинироваться между собой и с другими правилами, такими как required, min, max, typeError.


Любая числовая схема начинается с объявления типа:

import * as Yup from "yup";

const schema = Yup.object({
  amount: Yup.number()
});

На этом этапе значение уже приводится к числу, но не ограничивается по знаку или форме. Любые дополнительные ограничения добавляются через цепочку методов.


Положительные числа: positive()

Метод positive() ограничивает допустимые значения только числами больше нуля. Ноль при этом считается недопустимым значением.

const schema = Yup.object({
  price: Yup.number()
    .positive("Значение должно быть больше нуля")
});

Поведение positive():

  • допускаются значения: 0.1, 1, 100, 3.14
  • отклоняются значения: 0, -1, -10

Внутри YupResolver ошибка валидации передаётся в структуру errors, где ключ соответствует имени поля, а сообщение формируется из аргумента метода или стандартного сообщения библиотеки.

Комбинация с обязательностью поля:

price: Yup.number()
  .typeError("Введите число")
  .positive("Только положительное значение")
  .required("Поле обязательно")

Отрицательные числа: negative()

Метод negative() ограничивает значения строго отрицательными числами. Ноль не считается допустимым.

const schema = Yup.object({
  debt: Yup.number()
    .negative("Значение должно быть отрицательным")
});

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

  • -1, -10, -0.5

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

  • 0, 1, 100

Особенность применения в схемах через YupResolver заключается в том, что ошибка формируется на уровне схемы и не требует дополнительной логики в компоненте формы.

Комбинированный вариант:

debt: Yup.number()
  .typeError("Введите число")
  .negative("Должно быть отрицательное значение")
  .required("Поле обязательно")

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

Метод integer() ограничивает значение только целыми числами, исключая дробные значения. Это правило работает независимо от знака числа.

const schema = Yup.object({
  quantity: Yup.number()
    .integer("Допустимы только целые числа")
});

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

  • 1, 10, -5, 0

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

  • 1.5, 0.1, -3.14

При использовании с YupResolver дробное значение автоматически преобразуется в ошибку валидации, даже если оно корректно распознано как число на уровне JavaScript.


Комбинации positive, negative и integer

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

Положительное целое число

const schema = Yup.object({
  count: Yup.number()
    .positive("Только положительные значения")
    .integer("Только целые числа")
});

Результат:

  • разрешены: 1, 2, 100
  • запрещены: 0, 1.5, -1

Отрицательное целое число

const schema = Yup.object({
  loss: Yup.number()
    .negative("Только отрицательные значения")
    .integer("Только целые числа")
});

Результат:

  • разрешены: -1, -10, -100
  • запрещены: 0, 1, -1.2

Поведение в YupResolver

YupResolver выступает адаптером между схемой Yup и системой валидации формы. При каждом изменении значения:

  1. данные формы передаются в Yup-схему;
  2. выполняется последовательная проверка всех правил;
  3. при нарушении любого ограничения формируется объект ошибок;
  4. объект возвращается в форму и связывается с соответствующими полями.

Пример интеграции:

import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

const schema = Yup.object({
  amount: Yup.number()
    .positive()
    .integer()
});

const { register, handleSubmit, formState: { errors } } = useForm({
  resolver: yupResolver(schema)
});

Структура errors.amount.message будет содержать текст ошибки первого нарушенного правила в цепочке валидации.


Взаимодействие с преобразованием типов

При работе с HTML-формами значения приходят как строки. Yup выполняет автоматическое преобразование, но поведение зависит от содержимого:

  • "10"10 (корректное число)
  • "10.5"10.5 (валидное число для number(), но может нарушить integer())
  • ""NaN (требует required или typeError для обработки)

Поэтому при использовании positive, negative, integer часто добавляется явная обработка ошибок типа:

Yup.number()
  .typeError("Требуется числовое значение")
  .positive()
  .integer()

Приоритет ошибок

Если в схеме присутствует несколько ограничений, ошибка возвращается по первому нарушенному правилу, которое срабатывает в процессе проверки. Например:

Yup.number()
  .positive("Положительное число")
  .integer("Целое число")

Для значения -2.5 будет возвращена ошибка positive, так как проверка знака выполняется раньше логики проверки дробной части.


Практическое поведение в сложных схемах

В более сложных объектах схемы числовые ограничения часто используются вместе с зависимыми правилами:

const schema = Yup.object({
  minAge: Yup.number()
    .positive()
    .integer()
    .min(18, "Минимальный возраст 18"),

  maxAge: Yup.number()
    .positive()
    .integer()
    .max(65, "Максимальный возраст 65")
});

В таких случаях YupResolver агрегирует ошибки по каждому полю независимо, сохраняя изоляцию валидации.


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

Поведение методов positive, negative, integer не включает автоматическую нормализацию данных. Они только проверяют соответствие значения правилам. Любая трансформация должна быть определена отдельно через transform():

Yup.number()
  .transform((value, originalValue) => {
    return String(originalValue).trim() === "" ? undefined : value;
  })
  .positive()
  .integer()