Yup поддерживает динамическую подстановку данных в текст ошибок. Это позволяет формировать сообщения валидации на основе текущих значений, ограничений схемы и пользовательского контекста.
Интерполяция особенно полезна в случаях:
Yup использует шаблоны вида:
${parameter}
Подстановка выполняется автоматически при возникновении ошибки.
Пример:
import * as yup from 'yup';
const schema = yup.string().min(5, 'Минимальная длина: ${min}');
Проверка:
await schema.validate('abc');
Результат:
Минимальная длина: 5
Каждый метод Yup передаёт собственный набор параметров.
yup.string().min(5, 'Минимум ${min} символов')
Доступно:
${min}
yup.string().max(10, 'Максимум ${max} символов')
Доступно:
${max}
yup.string().length(8, 'Длина должна быть ${length}')
Доступно:
${length}
yup
.string()
.matches(/^\d+$/, 'Значение "${value}" должно содержать только цифры');
Доступно:
${value}
yup
.string()
.oneOf(['admin', 'user'], 'Допустимые значения: ${values}');
Доступно:
${values}
Результат:
Допустимые значения: admin, user
yup
.number()
.min(18, 'Возраст должен быть не меньше ${min}');
yup
.date()
.min(new Date('2025-01-01'), 'Дата должна быть позже ${min}');
${value}${value} содержит текущее проверяемое значение.
Пример:
const schema = yup.string().email(
'Адрес "${value}" не является корректным email'
);
Проверка:
await schema.validate('wrong-email');
Ошибка:
Адрес "wrong-email" не является корректным email
${path}${path} содержит путь к полю.
Особенно полезно при вложенных объектах.
Пример:
const schema = yup.object({
user: yup.object({
email: yup.string().required('${path} обязательно')
})
});
Ошибка:
user.email обязательно
const schema = yup.object({
profile: yup.object({
username: yup
.string()
.min(4, 'Поле ${path} должно содержать минимум ${min} символа')
})
});
Ошибка:
Поле profile.username должно содержать минимум 4 символа
Метод test() позволяет передавать собственные параметры
для шаблонов.
const schema = yup.string().test(
'starts-with',
'Значение должно начинаться с "${prefix}"',
function (value) {
const prefix = 'JS';
if (!value?.startsWith(prefix)) {
return this.createError({
message: 'Значение должно начинаться с "${prefix}"',
params: { prefix }
});
}
return true;
}
);
Ошибка:
Значение должно начинаться с "JS"
Ключ params определяет набор переменных для
интерполяции.
params: {
key: value
}
Пример:
const schema = yup.number().test(
'range',
'Число должно быть между ${min} и ${max}',
function (value) {
const min = 10;
const max = 20;
if (value < min || value > max) {
return this.createError({
params: { min, max }
});
}
return true;
}
);
const schema = yup.string().test(
'complex',
'Поле ${field} должно содержать от ${min} до ${max} символов',
function (value) {
const min = 3;
const max = 10;
if (value.length < min || value.length > max) {
return this.createError({
params: {
field: this.path,
min,
max
}
});
}
return true;
}
);
const schema = yup.string().required(
'Поле "${path}" обязательно'
);
Метод label() позволяет задавать человекочитаемое имя
поля.
const schema = yup
.string()
.label('Имя пользователя')
.required('${label} обязательно');
Ошибка:
Имя пользователя обязательно
const schema = yup.object({
login: yup
.string()
.label('Логин')
.min(5, '${label} должен содержать минимум ${min} символов')
});
const schema = yup.object({
type: yup.string(),
code: yup.string().when('type', {
is: 'admin',
then: schema =>
schema.required(
'Для типа "${value}" поле обязательно'
)
})
});
Yup поддерживает передачу контекста через validate().
await schema.validate(data, {
context: {
role: 'admin'
}
});
const schema = yup.string().test(
'role-check',
'Требуется роль ${role}',
function (value) {
const role = this.options.context.role;
if (value !== role) {
return this.createError({
params: { role }
});
}
return true;
}
);
Глобальные сообщения Yup также поддерживают шаблоны.
import { setLocale } from 'yup';
setLocale({
string: {
min: 'Минимум ${min} символов'
}
});
setLocale({
mixed: {
required: 'Поле ${path} обязательно'
},
number: {
min: 'Минимальное значение: ${min}',
max: 'Максимальное значение: ${max}'
}
});
const schema = yup.array().min(
2,
'Минимальное количество элементов: ${min}'
);
const schema = yup.object().shape({
name: yup.string().required('${path} обязательно'),
age: yup.number().min(18, '${path}: минимум ${min}')
});
В Yup сообщение может быть функцией.
const schema = yup.string().min(5, ({ min }) => {
return `Минимальная длина: ${min}`;
});
Функция получает объект параметров:
({
value,
originalValue,
path,
spec,
label,
min,
max
})
const schema = yup.string().min(5, ({ min, value }) => {
return `"${value}" слишком короткое. Минимум: ${min}`;
});
Шаблоны значительно упрощают мультиязычную поддержку.
setLocale({
mixed: {
required: '${label} является обязательным'
}
});
Смена языка:
setLocale({
mixed: {
required: '${label} is required'
}
});
const schema = yup
.string()
.transform(value => value?.trim())
.min(3, 'После обработки длина должна быть больше ${min}');
const schema = yup.string().test(
'username',
'Пользователь "${username}" уже существует',
async function (value) {
const exists = true;
if (exists) {
return this.createError({
params: {
username: value
}
});
}
return true;
}
);
const schema = yup.string().test(
'custom',
'${field} заполнено неверно',
function () {
return this.createError({
params: {
field: this.path
}
});
}
);
const schema = yup
.string()
.nullable()
.required('${path} не должно быть null');
const schema = yup.string().test(
'full',
'Поле ${field}: минимум ${min}, максимум ${max}',
function (value) {
return this.createError({
params: {
field: this.path,
min: 5,
max: 10
}
});
}
);
function minLengthMessage(field, min) {
return `${field} должно содержать минимум ${min} символов`;
}
Использование:
yup.string().min(5, minLengthMessage('Имя', 5));
Неправильно:
return this.createError({
message: 'Минимум ${min}'
});
${min} не будет заменён.
Правильно:
return this.createError({
message: 'Минимум ${min}',
params: {
min: 5
}
});
message: 'Минимум ${minimum}'
params: { min: 5 }
Подстановка не выполнится.
yup.string().required('${min}')
Метод required() не предоставляет min.
const schema = yup.object({
username: yup
.string()
.label('Имя пользователя')
.min(
5,
'${label} должно содержать минимум ${min} символов'
)
.max(
20,
'${label} должно содержать максимум ${max} символов'
),
password: yup
.string()
.label('Пароль')
.test(
'strong-password',
'${label} слишком простой',
function (value) {
const hasNumber = /\d/.test(value);
const hasUppercase = /[A-Z]/.test(value);
if (!hasNumber || !hasUppercase) {
return this.createError({
params: {
label: 'Пароль'
}
});
}
return true;
}
)
});
const schema = yup.string().test(
'access',
'Для доступа требуется уровень ${level}',
function (value) {
const level = this.options.context.level;
if (value !== level) {
return this.createError({
params: { level }
});
}
return true;
}
);
Проверка:
await schema.validate('user', {
context: {
level: 'admin'
}
});
Ошибка:
Для доступа требуется уровень admin
.label('Email')
делает ошибки значительно понятнее, чем:
user.profile.contacts.email
Хорошая практика:
'${label} обязательно'
'${label} должно быть больше ${min}'
'${label} должно быть меньше ${max}'
Лучше:
'Минимум ${min} символов'
чем:
'Минимум 5 символов'
Наиболее распространённые:
| Переменная | Описание |
|---|---|
${value} |
Текущее значение |
${path} |
Путь к полю |
${label} |
Человекочитаемое имя |
${min} |
Минимальное значение |
${max} |
Максимальное значение |
${length} |
Точная длина |
${values} |
Список допустимых значений |
import * as yup from 'yup';
const schema = yup.object({
email: yup
.string()
.label('Email')
.email('"${value}" не является корректным email')
.required('${label} обязателен'),
age: yup
.number()
.label('Возраст')
.min(18, '${label} должен быть не меньше ${min}')
.max(65, '${label} должен быть не больше ${max}')
});
schema.validate({
email: 'wrong-email',
age: 15
});
Ошибки:
"wrong-email" не является корректным email
Возраст должен быть не меньше 18