Библиотека Yup строит систему валидации на основе цепочек и композиций, где каждая схема представляет собой объект с набором правил. Несмотря на то что многие операции выглядят как «изменение» существующей схемы, внутренне чаще происходит создание новой версии с расширенной логикой. Это приводит к важному различию между логическим мутированием (изменением поведения схемы) и физическим изменением объекта.
Мутирование схем в практическом смысле включает несколько механизмов:
Наиболее прямой способ изменения структуры объекта — использование
метода shape. Он применяется к объектным схемам и позволяет
добавлять или заменять поля.
import * as Yup from 'yup';
const baseSchema = Yup.object({
name: Yup.string().required(),
});
const extendedSchema = baseSchema.shape({
age: Yup.number().min(0),
});
Поведение shape важно понимать в контексте внутреннего
устройства:
При работе с динамическими формами именно shape
становится ключевым инструментом эволюции схемы без полного пересоздания
структуры.
Метод concat позволяет объединять две схемы одного типа,
создавая новую, которая наследует правила обеих.
const schemaA = Yup.string().min(3);
const schemaB = Yup.string().max(10);
const merged = schemaA.concat(schemaB);
Особенности композиции:
В отличие от shape, concat ближе к
функциональной композиции, а не к структурному изменению.
Одним из наиболее мощных механизмов «условного мутирования» является
when. Он позволяет изменять поведение схемы в зависимости
от внешних значений.
const schema = Yup.object({
isCompany: Yup.boolean(),
vatId: Yup.string().when('isCompany', {
is: true,
then: (s) => s.required(),
otherwise: (s) => s.notRequired(),
}),
});
Внутри when происходит не изменение исходной схемы, а
построение новой ветки логики на этапе выполнения валидации.
Ключевые характеристики:
Механизм lazy используется для построения схемы в момент
проверки, что позволяет реализовывать рекурсивные и сильно динамические
структуры.
const schema = Yup.lazy((value) => {
if (typeof value === 'string') {
return Yup.string().min(3);
}
return Yup.object();
});
Особенности:
Глобальное расширение функциональности достигается через
addMethod. Этот механизм изменяет поведение прототипов
схем, фактически мутируя библиотеку на уровне типов.
Yup.addMethod(Yup.string, 'startsWithA', function () {
return this.test('startsWithA', function (value) {
return value?.startsWith('A');
});
});
После этого метод становится доступным для всех строковых схем:
Yup.string().startsWithA();
Особенности:
Метод test является базовым способом добавления
кастомной логики проверки. Хотя он не изменяет структуру схемы, он
фактически «встраивает» дополнительное правило в существующую
цепочку.
const schema = Yup.string().test(
'is-even-length',
'Длина должна быть чётной',
(value) => value?.length % 2 === 0
);
Характеристика:
При композиции и расширении схем важно учитывать, что многие операции возвращают новые экземпляры. Это создаёт эффект «контролируемого копирования».
const base = Yup.string().min(3);
const variant = base.min(5);
В этом случае:
base остаётся неизменным;variant представляет новую схему;Такое поведение снижает риск непреднамеренного глобального мутирования.
Функция reach позволяет адресно изменять вложенные поля
без полного пересоздания структуры.
const schema = Yup.object({
user: Yup.object({
profile: Yup.object({
age: Yup.number(),
}),
}),
});
const ageSchema = Yup.reach(schema, 'user.profile.age');
Далее полученная схема может быть модифицирована независимо, что создаёт эффект точечного мутирования.
Метод transform изменяет входные данные до проверки, что
косвенно влияет на поведение схемы.
const schema = Yup.number().transform((value, originalValue) => {
return originalValue === '' ? null : value;
});
Здесь происходит:
Опция stripUnknown влияет на итоговую форму объекта,
удаляя неизвестные поля.
const schema = Yup.object({
name: Yup.string(),
}).noUnknown(true);
Это создаёт эффект пост-обработки, при котором результат валидации отличается от входного объекта, что можно рассматривать как структурное мутирование результата.
Система ссылок ref позволяет создавать зависимые схемы,
где поведение одного поля зависит от другого.
const schema = Yup.object({
password: Yup.string(),
confirm: Yup.string().oneOf([Yup.ref('password')]),
});
Здесь схема не изменяется напрямую, но её поведение динамически зависит от состояния других полей, что формирует связанный граф зависимостей.
Мутирование схем в Yup складывается из нескольких уровней:
shape;concat;when и
lazy;addMethod;test и
transform;reach;ref.Эти механизмы формируют гибкую систему, в которой схемы могут как эволюционировать во времени, так и изменять своё поведение в зависимости от данных и контекста выполнения.