Валидация файлов в схемах, построенных на основе Yup, опирается на
обработку объектов типа File и FileList,
которые предоставляются браузерным API. При использовании резолвера
React Hook Form через yupResolver такие данные проходят через единый
слой преобразования и проверки, где схема становится источником строгих
правил для загружаемого содержимого.
Браузерные файлы представлены двумя основными структурами:
File — единичный файл с метаданнымиFileList — коллекция файлов, получаемая через
<input type="file" />Объект File содержит ключевые свойства:
name — имя файлаsize — размер в байтахtype — MIME-типlastModified — дата последнего измененияПри валидации через Yup важно учитывать, что FileList не
является массивом в полном смысле, поэтому часто требуется приведение к
массиву:
const filesArray = (value) => {
if (!value) return [];
return Array.from(value);
};
Простейшая схема в Yup может проверять наличие файла:
import * as Yup from "yup";
const schema = Yup.object({
file: Yup.mixed().required("Файл обязателен"),
});
Тип mixed() используется потому, что файл не относится к
примитивным типам.
Одним из ключевых ограничений является контроль размера:
const schema = Yup.object({
file: Yup.mixed()
.required("Файл обязателен")
.test("fileSize", "Файл слишком большой", (value) => {
return value && value.size <= 5 * 1024 * 1024;
}),
});
Логика проверки строится вокруг свойства size,
измеряемого в байтах. Ограничение в 5 MB часто используется как базовый
порог для изображений и документов.
Контроль формата файла реализуется через type:
const schema = Yup.object({
file: Yup.mixed()
.required("Файл обязателен")
.test("fileType", "Неподдерживаемый формат", (value) => {
if (!value) return false;
return ["image/jpeg", "image/png", "application/pdf"].includes(value.type);
}),
});
Такой подход предотвращает загрузку неподдерживаемых или потенциально опасных форматов.
При работе с множественной загрузкой применяется массив файлов:
const schema = Yup.object({
files: Yup.array()
.of(Yup.mixed())
.min(1, "Необходимо загрузить хотя бы один файл")
.max(5, "Максимум 5 файлов"),
});
Дополнительно можно валидировать каждый элемент массива:
const fileSchema = Yup.mixed()
.test("fileSize", "Слишком большой файл", (file) => {
return file && file.size <= 3 * 1024 * 1024;
});
const schema = Yup.object({
files: Yup.array().of(fileSchema),
});
Метод test является основным механизмом расширения
логики:
const schema = Yup.object({
file: Yup.mixed().test(
"is-image",
"Только изображения",
(value) => {
return value && value.type.startsWith("image/");
}
),
});
В рамках test доступен полный контроль над объектом
файла, включая комбинацию нескольких условий.
Для графических файлов часто требуется проверка размеров изображения:
const validateImageDimensions = (file) =>
new Promise((resolve) => {
const img = new Image();
img.src = URL.createObjectURL(file);
img.onl oad = () => {
const valid = img.width <= 1920 && img.height <= 1080;
resolve(valid);
};
img.oner ror = () => resolve(false);
});
Интеграция с Yup:
const schema = Yup.object({
image: Yup.mixed().test(
"dimensions",
"Недопустимое разрешение",
async (file) => {
if (!file) return false;
return await validateImageDimensions(file);
}
),
});
Yup поддерживает асинхронные проверки, что особенно важно для файлов:
Пример асинхронной проверки:
const checkFileOnServer = async (file) => {
const formData = new FormData();
formData.append("file", file);
const res = await fetch("/api/validate-file", {
method: "POST",
body: formData,
});
const data = await res.json();
return data.valid;
};
Схема:
const schema = Yup.object({
file: Yup.mixed().test(
"server-validation",
"Файл не прошёл проверку сервера",
async (file) => {
if (!file) return false;
return await checkFileOnServer(file);
}
),
});
Связка React Hook Form и Yup позволяет централизовать управление файлами:
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
const schema = Yup.object({
file: Yup.mixed()
.required()
.test("fileSize", "Слишком большой файл", (file) => {
return file && file.size <= 2 * 1024 * 1024;
}),
});
const { register, handleSubmit, formState } = useForm({
resolver: yupResolver(schema),
});
HTML-интеграция:
<input type="file" {...register("file")} />
При отправке формы файл автоматически попадает в схему и проходит все проверки.
Часто требуется преобразование FileList в массив:
const schema = Yup.object({
files: Yup.mixed().transform((value) => {
if (!value) return [];
return Array.from(value);
}),
});
Это позволяет унифицировать обработку данных на уровне схемы.
Ошибки в Yup имеют стандартную структуру:
path — поле, где произошла ошибкаmessage — текст ошибкиtype — тип правилаПример:
{
path: "file",
message: "Файл слишком большой",
type: "fileSize"
}
При использовании resolver эти ошибки автоматически передаются в
React Hook Form и становятся доступны через
formState.errors.
const schema = Yup.object({
file: Yup.mixed()
.required()
.test("fileType", "Только PDF", (file) => {
return file?.type === "application/pdf";
})
.test("fileSize", "Максимум 10MB", (file) => {
return file && file.size <= 10 * 1024 * 1024;
}),
});
files: Yup.array()
.of(
Yup.mixed()
.test("size", "Файл слишком большой", (f) => f.size < 5e6)
.test("type", "Недопустимый тип", (f) => f.name.endsWith(".zip"))
)
При работе с большими файлами важно учитывать:
URL.createObjectURLURL.revokeObjectURLСхемы Yup в связке с resolver используются как первый уровень фильтрации, снижая нагрузку на backend и предотвращая отправку заведомо некорректных файлов.