В Yup трансформация данных выполняется на уровне схемы в момент
валидации и приведения значений к ожидаемым типам. Это позволяет не
только проверять данные, но и нормализовать их перед тем, как они
попадут в бизнес-логику приложения. В связке с резолверами, такими как
@hookform/resolvers/yup, трансформация становится частью
общего пайплайна обработки формы: сырые значения из UI сначала
преобразуются схемой, затем проходят проверку, и только после этого
возвращаются в форму или передаются дальше.
Метод transform() является ключевым инструментом
изменения входных данных внутри Yup-схемы. Он применяется ко всем
основным типам: строкам, числам, булевым значениям и даже объектам.
Сигнатура метода:
schema.transform((value, originalValue) => {
return transformedValue;
});
value — текущее значение после предыдущих
преобразованийoriginalValue — исходное значение, полученное из формы
или внешнего источникаОдна из наиболее частых задач — преобразование строкового ввода в числовой формат:
import * as Yup from "yup";
const schema = Yup.object({
age: Yup.number()
.transform((value, originalValue) => {
return originalValue === "" ? null : Number(originalValue);
})
.nullable()
});
В данном случае пустая строка не превращается в 0, что
предотвращает логические ошибки при обработке форм.
transform() часто используется для нормализации
строк:
const schema = Yup.object({
username: Yup.string()
.transform((value) => {
return value ? value.trim().toLowerCase() : value;
})
});
Такая трансформация устраняет лишние пробелы и приводит значения к единому регистру.
Yup обладает встроенной системой приведения типов (type casting),
которая активируется до этапа валидации. Однако её поведение можно
переопределять через transform().
const schema = Yup.object({
isActive: Yup.boolean().transform((value, originalValue) => {
if (originalValue === "true") return true;
if (originalValue === "false") return false;
return value;
})
});
Без явной трансформации строковые значения могли бы интерпретироваться некорректно или вызывать ошибки валидации.
Yup часто интерпретирует пустые строки как валидные значения, что требует ручной обработки:
const schema = Yup.object({
description: Yup.string().transform((value, originalValue) => {
return originalValue === "" ? undefined : value;
})
});
Такое преобразование позволяет корректно использовать
required() без ложных срабатываний.
Метод cast() используется для преобразования
произвольного значения в тип, определённый схемой, без запуска полной
валидации.
const schema = Yup.number();
schema.cast("42"); // 42
В отличие от validate(), метод cast():
const schema = Yup.object({
id: Yup.number(),
tags: Yup.array().of(Yup.string())
});
const result = schema.cast({
id: "10",
tags: [1, 2, 3]
});
Результат:
{
id: 10,
tags: ["1", "2", "3"]
}
Это особенно важно при работе с API, где типы данных часто не соответствуют ожидаемым.
Метод default() задаёт значение, которое применяется до
валидации и трансформации.
const schema = Yup.object({
role: Yup.string().default("user")
});
При отсутствии значения поле автоматически получит
"user".
Порядок обработки:
default()transform()const schema = Yup.object({
code: Yup.string()
.default(" abc ")
.transform((value) => value.trim())
});
Результат всегда будет "abc".
Трансформация особенно важна при работе со сложными структурами данных.
const schema = Yup.object({
tags: Yup.array()
.transform((value) => {
return Array.isArray(value)
? value.filter(Boolean)
: [];
})
});
Здесь удаляются falsy-значения (null,
undefined, "", 0).
const schema = Yup.object({
user: Yup.object({
name: Yup.string().transform((v) => v?.trim()),
age: Yup.number().transform((v, ov) => Number(ov))
})
});
Каждое поле обрабатывается независимо, что позволяет гибко нормализовать вложенные структуры.
В связке с @hookform/resolvers/yup трансформации
применяются до возврата результата в React Hook Form. Это означает,
что:
onSubmiterrors формируются уже на основе трансформированных
данныхПример использования:
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
const schema = Yup.object({
price: Yup.number()
.transform((v, ov) => Number(ov))
});
const { register, handleSubmit } = useForm({
resolver: yupResolver(schema)
});
В этом случае строковое значение "100" автоматически
преобразуется в 100 до этапа проверки.
Внутренний пайплайн Yup можно описать следующим образом:
default()transform()required, min,
max, matches и др.)Понимание этого порядка критично для предсказуемого поведения схем.
Несколько transform() могут применяться
последовательно:
const schema = Yup.string()
.transform((v) => v.trim())
.transform((v) => v.toLowerCase())
.transform((v) => v.replace(/\s+/g, "-"));
Каждый этап получает результат предыдущего, формируя конвейер обработки данных.
Трансформация не должна использоваться для бизнес-логики. Её задача ограничена:
Сложные вычисления внутри transform() могут привести
к:
При необходимости сложной логики предпочтительно выносить её за пределы схемы и использовать промежуточные слои обработки данных.