Валидация сложных форм и структур данных редко требует проверки всего
объекта целиком. На практике часто возникает необходимость валидировать
только часть полей — например, при редактировании профиля пользователя,
пошаговых формах или динамически изменяемых схемах. В таких сценариях в
Yup ключевую роль играют методы pick и omit,
позволяющие создавать производные схемы на основе существующих.
В основе работы с частичной валидацией лежит объектная схема:
import * as Yup from 'yup';
const userSchema = Yup.object({
name: Yup.string().required(),
email: Yup.string().email().required(),
age: Yup.number().min(18),
password: Yup.string().min(8),
role: Yup.string().oneOf(['user', 'admin']),
});
Такая схема описывает полный набор полей. Однако не всегда требуется валидировать их одновременно. В некоторых случаях важно сузить контекст проверки.
Метод pick позволяет создать новую схему, включающую
только указанные поля исходной схемы. Это полезно при создании частичных
форм или API-валидации отдельных частей объекта.
const loginSchema = userSchema.pick(['email', 'password']);
В результате получается схема, содержащая только email и
password, со всеми их оригинальными правилами
валидации.
При использовании pick важно учитывать, что он работает
только на верхнем уровне объекта. Вложенные схемы остаются
неизменными.
const profileSchema = Yup.object({
user: Yup.object({
name: Yup.string(),
email: Yup.string(),
}),
settings: Yup.object({
theme: Yup.string(),
}),
});
const userOnlySchema = profileSchema.pick(['user']);
Здесь сохраняется вся структура поля user, включая его
внутренние правила.
Обратным инструментом является omit. Он создаёт новую
схему, исключая перечисленные поля из исходной.
const publicUserSchema = userSchema.omit(['password']);
Такой подход часто используется при формировании публичных API-ответов или отображении данных без чувствительных полей.
Оба метода решают схожую задачу, но подходят к ней с разных сторон:
pick — формирует «белый список» полейomit — формирует «чёрный список» полейВыбор между ними зависит от характера задачи. Если список полей
фиксирован и небольшой, чаще применяется pick. Если
необходимо исключить несколько полей из большой схемы, удобнее
использовать omit.
В реальных проектах методы часто комбинируются для гибкого управления схемами:
const baseSchema = Yup.object({
name: Yup.string(),
email: Yup.string(),
password: Yup.string(),
role: Yup.string(),
createdAt: Yup.date(),
});
const editableSchema = baseSchema
.omit(['createdAt'])
.pick(['name', 'email', 'role']);
В данном случае сначала исключается поле createdAt,
затем выбирается подмножество оставшихся полей. Такой подход позволяет
строить промежуточные уровни абстракции.
В интерфейсах редактирования данных часто требуется проверять только изменяемые поля. Например, пользователь может обновлять профиль без изменения пароля.
const updateProfileSchema = userSchema.omit(['password']);
Это позволяет переиспользовать базовую схему без дублирования логики.
В приложениях с гибкими интерфейсами схемы часто формируются на лету:
function createSchema(fields) {
return userSchema.pick(fields);
}
const schema = createSchema(['email', 'role']);
Такой подход удобен при работе с конфигурационными формами, где набор полей зависит от ролей пользователя или состояния интерфейса.
При использовании pick и omit Yup
пересчитывает структуру схемы, но сохраняет исходные правила валидации
для оставшихся полей. Ошибки будут возвращаться только для активных
полей схемы.
Это особенно важно при работе с формами, где неактуальные поля не должны влиять на результат проверки.
Методы частичной валидации не рекурсивны. Это означает, что они не «проникают» внутрь массивов и вложенных объектов без явного указания.
const schema = Yup.object({
user: Yup.object({
name: Yup.string(),
email: Yup.string(),
}),
tags: Yup.array().of(Yup.string()),
});
const partial = schema.pick(['user']);
В этом случае поле tags полностью исключается, но
структура user остаётся нетронутой.
В архитектурах с разделением форм на шаги (wizard forms)
частичная валидация становится ключевым инструментом. Каждый шаг может
иметь собственную схему, полученную из базовой:
const step1Schema = userSchema.pick(['email']);
const step2Schema = userSchema.pick(['password']);
const step3Schema = userSchema.pick(['name', 'role']);
Такой подход позволяет централизованно управлять правилами валидации и избегать дублирования.
При использовании Yup вместе с TypeScript частичная валидация влияет
и на типы. Однако важно учитывать, что pick и
omit не всегда автоматически корректно выводят строгие типы
без дополнительной утилиты InferType.
import * as Yup from 'yup';
const schema = Yup.object({
name: Yup.string().required(),
age: Yup.number(),
});
type User = Yup.InferType<typeof schema>;
const partial = schema.pick(['name']);
type PartialUser = Yup.InferType<typeof partial>;
Тип PartialUser будет содержать только выбранные
поля.
Несмотря на удобство, pick и omit имеют ряд
ограничений:
В сложных сценариях может потребоваться комбинирование с
when, lazy или ручное построение схем.
Использование частичной валидации снижает необходимость дублирования
схем, что положительно влияет на поддержку кода. Однако при частом
создании новых схем через pick и omit в
runtime может увеличиваться накладная стоимость создания объектов.
В большинстве приложений это не является критичным, но в высоконагруженных интерфейсах имеет смысл кэшировать производные схемы.
В крупных проектах базовая схема обычно рассматривается как источник истины:
export const userSchema = Yup.object({
name: Yup.string(),
email: Yup.string(),
password: Yup.string(),
role: Yup.string(),
});
Далее производные схемы формируются через частичную выборку:
export const authSchema = userSchema.pick(['email', 'password']);
export const profileSchema = userSchema.omit(['password']);
Такой подход упрощает поддержку и синхронизацию бизнес-логики валидации.
По мере роста приложения количество сценариев использования одной
сущности увеличивается. Полная схема становится универсальным
контрактом, а pick и omit — инструментами
адаптации под конкретные контексты.
Это позволяет: