Проверка неизвестных ключей: noUnknown

Поведение объектов по умолчанию

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

Такое поведение удобно при работе с гибкими API, где входные данные могут содержать дополнительные метаданные. Однако в строго типизированных сценариях это приводит к тому, что лишние или потенциально опасные поля проходят незамеченными.

import * as Yup from 'yup';

const schema = Yup.object({
  name: Yup.string().required(),
});

schema.validateSync({
  name: 'Alex',
  role: 'admin', // игнорируется
});

В приведённом примере поле role не описано в схеме, но валидация всё равно проходит успешно.


Назначение механизма noUnknown

Механизм noUnknown предназначен для строгого контроля структуры объекта. Он запрещает наличие свойств, которые не были явно определены в схеме. Это позволяет:

  • фиксировать структуру входных данных;
  • предотвращать передачу лишних полей;
  • снижать риск утечки или обработки неожиданных данных;
  • обеспечивать более строгую контрактность API.

Базовое использование noUnknown

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

const schema = Yup.object({
  name: Yup.string().required(),
}).noUnknown();

При попытке валидации объекта с дополнительными полями будет выброшена ошибка:

schema.validateSync({
  name: 'Alex',
  role: 'admin',
});

Результат: ошибка валидации, так как role не описан в схеме.


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

noUnknown поддерживает кастомизацию сообщения об ошибке. Вторым аргументом передаётся текст, который будет использоваться при нарушении правила.

const schema = Yup.object({
  name: Yup.string().required(),
}).noUnknown('Обнаружены недопустимые поля');

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


Строгий режим и взаимодействие с noUnknown

Yup предоставляет возможность строгой валидации через режим strict. Однако strict влияет на преобразование значений, тогда как noUnknown контролирует структуру объекта.

Эти механизмы решают разные задачи:

  • strict: true — отключает кастинг и преобразования;
  • noUnknown() — запрещает неизвестные ключи.
const schema = Yup.object({
  age: Yup.number(),
})
  .noUnknown()
  .strict();

Совместное использование усиливает контроль над входными данными, но не заменяет друг друга.


Альтернатива: stripUnknown

Вместо запрета лишних ключей может применяться их автоматическое удаление. Это реализуется через опцию stripUnknown.

const schema = Yup.object({
  name: Yup.string(),
});

const result = await schema.validate(
  {
    name: 'Alex',
    role: 'admin',
  },
  { stripUnknown: true }
);

В результате поле role будет удалено из объекта, а не вызовет ошибку.

Разница подходов:

  • noUnknown — строгая ошибка при лишних полях;
  • stripUnknown — автоматическое удаление лишних полей.

Поведение с вложенными объектами

noUnknown не применяется рекурсивно автоматически. Для вложенных объектов правило необходимо задавать явно на каждом уровне схемы.

const schema = Yup.object({
  user: Yup.object({
    name: Yup.string(),
  }).noUnknown(),
}).noUnknown();

В данном случае:

  • лишние ключи в user будут запрещены;
  • лишние ключи на верхнем уровне также будут запрещены.

Объекты внутри массивов

При использовании массивов объектов проверка также должна задаваться внутри схемы элементов массива.

const schema = Yup.object({
  users: Yup.array().of(
    Yup.object({
      name: Yup.string(),
    }).noUnknown()
  ),
}).noUnknown();

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


Особенности поведения при частичной валидации

При использовании методов validateAt или частичной проверки объекта, noUnknown продолжает действовать только в рамках проверяемой схемы. Это означает, что контроль ограничивается текущим уровнем структуры, без анализа всего объекта целиком.


Влияние на типизацию и контракт данных

При использовании TypeScript noUnknown усиливает соответствие между типами и реальными данными. Несмотря на то, что типизация описывает ожидаемую структуру, JavaScript-объекты могут содержать дополнительные поля. Проверка через noUnknown фиксирует реальную форму данных во время выполнения.


Комбинирование с трансформациями

При наличии трансформаций (transform) порядок обработки влияет на результат:

  1. трансформация значения;
  2. проверка структуры;
  3. применение noUnknown.

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

const schema = Yup.object({
  name: Yup.string(),
})
  .transform((value) => ({
    ...value,
    injected: true,
  }))
  .noUnknown();

Поле injected будет расценено как лишнее.


Практическая строгость схем

Использование noUnknown становится особенно значимым в системах, где входные данные поступают из внешних источников: формы, API, очереди сообщений. В таких сценариях контроль структуры снижает вероятность непредсказуемого поведения логики обработки данных.


Поведение при пустых объектах

Пустой объект считается валидным, если не нарушает другие ограничения схемы. noUnknown не запрещает отсутствие полей, он запрещает только наличие неописанных свойств.

const schema = Yup.object({
  name: Yup.string(),
}).noUnknown();

schema.validateSync({});

Валидация проходит успешно.