Библиотека Yup предоставляет механизм расширения стандартных схем через добавление пользовательских методов на уровне прототипов. Это позволяет централизованно определять повторно используемую логику валидации и интегрировать её во все экземпляры схем без дублирования кода.
Каждый тип схемы в Yup (string, number, object, array и др.) наследуется от базового класса Schema. Именно этот уровень используется для добавления глобальных методов, доступных во всех экземплярах соответствующего типа.
Механизм расширения строится вокруг функции addMethod,
которая привязывает новый метод к прототипу схемы:
import * as Yup from 'yup';
Yup.addMethod(Yup.string, 'onlyLetters', function (message) {
return this.test('only-letters', message, function (value) {
const { path, createError } = this;
if (!value) return true;
return /^[A-Za-zА-Яа-я]+$/.test(value)
? true
: createError({ path, message });
});
});
После регистрации метод становится доступен для всех строковых схем:
const schema = Yup.string().onlyLetters('Допустимы только буквы');
Функция addMethod принимает три параметра:
Yup.string)Внутри происходит расширение прототипа, поэтому все последующие экземпляры автоматически получают новый метод.
Yup.addMethod(schemaType, methodName, methodImplementation);
Ключевой особенностью является контекст this, который
внутри метода указывает на текущую схему. Это позволяет комбинировать
встроенные методы Yup с пользовательскими.
Глобальные методы часто используются для стандартизации правил валидации в рамках приложения. Например, проверка диапазона длины строки:
Yup.addMethod(Yup.string, 'betweenLength', function (min, max, message) {
return this.min(min, message).max(max, message);
});
Использование:
const schema = Yup.string().betweenLength(5, 20, 'Недопустимая длина');
Подобный подход уменьшает количество повторяющейся логики в схемах и делает правила более декларативными.
Глобальные методы могут быть специфичны для типа данных. Для чисел часто добавляются проверки бизнес-логики:
Yup.addMethod(Yup.number, 'isEven', function (message) {
return this.test('is-even', message, function (value) {
if (value === undefined || value === null) return true;
return value % 2 === 0;
});
});
Применение:
const schema = Yup.number().isEven('Число должно быть чётным');
Глобальные методы можно комбинировать с уже существующими методами Yup. Это позволяет строить сложные правила без потери читаемости:
Yup.addMethod(Yup.string, 'strictEmail', function () {
return this.email().trim().lowercase();
});
Такая композиция превращает набор простых трансформаций в единый переиспользуемый контракт валидации.
Для объектов глобальные методы часто используются для кросс-полевой валидации:
Yup.addMethod(Yup.object, 'atLeastOneRequired', function (fields, message) {
return this.test('at-least-one-required', message, function (value) {
const { path, createError } = this;
const hasValue = fields.some(
(field) => value && value[field] !== undefined && value[field] !== ''
);
return hasValue
? true
: createError({ path, message });
});
});
Пример использования:
const schema = Yup.object({
phone: Yup.string(),
email: Yup.string(),
}).atLeastOneRequired(['phone', 'email'], 'Необходимо заполнить хотя бы одно поле');
При добавлении глобальных методов важно учитывать возможные конфликты имён. Повторное определение метода приведёт к перезаписи поведения. Для минимизации рисков используются:
Yup.addMethod(Yup.string, 'app_onlyLetters', function () {
return this.matches(/^[A-Za-z]+$/);
});
При использовании TypeScript требуется явное расширение типов, иначе новые методы не будут распознаны системой типов.
declare module 'yup' {
interface StringSchema {
onlyLetters(message?: string): StringSchema;
}
}
Это позволяет сохранять типобезопасность при работе с расширенными схемами.
В крупных проектах глобальные методы выносятся в отдельные модули:
// validators/string.js
import * as Yup from 'yup';
export function registerStringValidators() {
Yup.addMethod(Yup.string, 'noSpaces', function (message) {
return this.test('no-spaces', message, value => {
if (!value) return true;
return !/\s/.test(value);
});
});
}
Инициализация выполняется один раз при запуске приложения, после чего методы становятся доступны во всех схемах.
Глобальные методы органично встраиваются в цепочки Yup:
const schema = Yup.string()
.required()
.trim()
.noSpaces()
.min(5);
Порядок вызовов имеет значение, так как каждый метод возвращает новую модифицированную схему.
Несмотря на гибкость, механизм глобальных методов имеет ряд ограничений:
Эти факторы делают целесообразным централизованный подход к регистрации расширений и строгую структуру именования методов