В Yup преобразование данных играет не менее важную роль, чем сама проверка значений. Помимо проверки типов, ограничений и обязательности полей, библиотека предоставляет механизм изменения итогового значения через методы трансформации.
Преобразование позволяет:
Основным инструментом является метод transform().
При обработке значения Yup выполняет несколько этапов:
transform).cast).validate).Пример:
import * as yup from 'yup';
const schema = yup.string().transform((value) => {
return value.trim();
});
const result = await schema.validate(' hello ');
console.log(result);
Результат:
hello
Исходная строка была преобразована до проверки результата.
transform((currentValue, originalValue) => {})
Параметры:
| Параметр | Описание |
|---|---|
currentValue |
Текущее значение после предыдущих преобразований |
originalValue |
Исходное значение до любых изменений |
Пример:
const schema = yup.string().transform((value, originalValue) => {
console.log(value);
console.log(originalValue);
return value;
});
Удаление пробелов:
const schema = yup.string().transform((value) => {
return value.trim();
});
Использование:
const result = await schema.validate(' admin ');
console.log(result);
Результат:
admin
const schema = yup.string().transform((value) => {
return value.toLowerCase();
});
const schema = yup.string().transform((value) => {
return value.toUpperCase();
});
Пример:
const result = await schema.validate('JavaScript');
console.log(result);
Результат:
JAVASCRIPT
Преобразования выполняются последовательно.
const schema = yup
.string()
.transform((value) => value.trim())
.transform((value) => value.toLowerCase())
.transform((value) => value.replace(/\s+/g, '-'));
Использование:
const result = await schema.validate(' Hello World ');
console.log(result);
Результат:
hello-world
originalValue содержит исходные данные до любых
преобразований.
const schema = yup.string().transform((value, originalValue) => {
console.log('Текущее:', value);
console.log('Исходное:', originalValue);
return value.trim();
});
Одна из самых распространённых задач.
const schema = yup.string().transform((value) => {
return value === '' ? null : value;
}).nullable();
Пример:
const result = await schema.validate('');
console.log(result);
Результат:
null
const schema = yup.number().transform((value, originalValue) => {
return Number(originalValue);
});
Пример:
const result = await schema.validate('42');
console.log(result);
Результат:
42
const schema = yup.number().transform((value, originalValue) => {
const parsed = Number(originalValue);
return isNaN(parsed) ? undefined : parsed;
});
const schema = yup.date().transform((value, originalValue) => {
return new Date(originalValue);
});
const schema = yup.string().transform((value) => {
return value.replace(/\D/g, '');
});
Использование:
const result = await schema.validate('+7 (777) 123-45-67');
console.log(result);
Результат:
77771234567
const schema = yup
.string()
.email()
.transform((value) => value.trim().toLowerCase());
const schema = yup.array().transform((value) => {
return value.map(item => item.trim());
});
Пример:
const result = await schema.validate([
' one ',
' two ',
' three '
]);
console.log(result);
Результат:
['one', 'two', 'three']
const schema = yup.array().transform((value) => {
return value.filter(Boolean);
});
const schema = yup.array().transform((value) => {
return [...new Set(value)];
});
const schema = yup.object({
name: yup.string(),
city: yup.string()
}).transform((value) => {
return {
...value,
name: value.name?.trim(),
city: value.city?.trim()
};
});
const schema = yup.object().transform((value) => {
return {
firstName: value.name,
age: value.age
};
});
const schema = yup.object().transform((value) => {
return {
id: value.id,
email: value.email
};
});
const schema = yup.object({
profile: yup.object({
firstName: yup.string(),
lastName: yup.string()
})
}).transform((value) => {
return {
...value,
profile: {
...value.profile,
firstName: value.profile.firstName.trim(),
lastName: value.profile.lastName.trim()
}
};
});
cast() выполняет преобразование без валидации.
const schema = yup.number();
const result = schema.cast('25');
console.log(result);
Результат:
25
По умолчанию Yup пытается приводить типы автоматически.
const schema = yup.number();
await schema.validate('42');
Результат:
42
При использовании strict() автоматическое преобразование
отключается.
const schema = yup.number().strict();
await schema.validate('42');
Ошибка:
this must be a `number` type
transform() не применяется в strict-режиме.
const schema = yup
.string()
.strict()
.transform(value => value.trim());
Преобразование часто комбинируется со значениями по умолчанию.
const schema = yup.string()
.transform(value => value?.trim())
.default('guest');
const schema = yup
.string()
.nullable()
.transform(value => value === '' ? null : value);
const schema = yup.boolean().transform((value, originalValue) => {
if (originalValue === 'true') {
return true;
}
if (originalValue === 'false') {
return false;
}
return value;
});
Типичный пример для frontend-приложений.
const schema = yup.object({
name: yup.string()
.transform(v => v.trim()),
email: yup.string()
.transform(v => v.trim().toLowerCase()),
age: yup.number(),
phone: yup.string()
.transform(v => v.replace(/\D/g, ''))
});
const schema = yup.string().transform((value) => {
return value.replace(/<[^>]*>?/gm, '');
});
const schema = yup.string().transform((value) => {
return value
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^\w-]+/g, '');
});
Пример:
const result = await schema.validate(' Hello JavaScript World! ');
console.log(result);
Результат:
hello-javascript-world
const schema = yup.object({
type: yup.string(),
value: yup.string().when('type', {
is: 'email',
then: schema =>
schema.transform(v => v.toLowerCase()),
otherwise: schema =>
schema.transform(v => v.trim())
})
});
Частая ошибка при преобразовании — вызов методов строки у
undefined.
Небезопасный вариант:
.transform(value => value.trim())
Безопасный вариант:
.transform(value => value?.trim())
const schema = yup.object({
username: yup.string()
.transform(v => v.trim().toLowerCase()),
tags: yup.array()
.transform(v => [...new Set(v)])
});
import * as yup from 'yup';
const userSchema = yup.object({
name: yup.string()
.required()
.transform(v => v?.trim()),
email: yup.string()
.email()
.required()
.transform(v => v?.trim().toLowerCase()),
age: yup.number()
.transform((v, original) => {
const parsed = Number(original);
return isNaN(parsed) ? undefined : parsed;
}),
phone: yup.string()
.transform(v => v?.replace(/\D/g, '')),
website: yup.string()
.transform(v => v === '' ? null : v)
.nullable(),
tags: yup.array()
.transform(v => [...new Set(v)])
});
const result = await userSchema.validate({
name: ' Alex ',
email: ' ADMIN@MAIL.COM ',
age: '25',
phone: '+7 (777) 123-45-67',
website: '',
tags: ['js', 'js', 'node']
});
console.log(result);
Результат:
{
name: 'Alex',
email: 'admin@mail.com',
age: 25,
phone: '77771234567',
website: null,
tags: ['js', 'node']
}
Последовательность имеет значение.
const schema = yup.string()
.transform(v => v.trim())
.transform(v => v.toLowerCase());
Сначала:
" Hello "
станет:
"Hello"
затем:
"hello"
.transform(() => undefined)
Может приводить к неожиданным ошибкам required-полей.
.transform(() => 'text')
для объекта:
yup.object()
Нарушает ожидаемую структуру схемы.
Плохой вариант:
.transform(value => {
value.name = value.name.trim();
return value;
})
Безопасный вариант:
.transform(value => ({
...value,
name: value.name.trim()
}))
Трансформации выполняются при каждой валидации.
Нежелательно: