Ограничение размера файла в схемах валидации на базе Yup реализуется
через кастомные проверки, поскольку стандартные примитивы библиотеки
ориентированы на строковые, числовые и логические типы. При работе с
загрузкой файлов в веб-приложениях значение поля обычно представлено
объектом File или массивом FileList, где
ключевым параметром становится свойство size, выраженное в
байтах.
Объект File в браузере содержит метаданные, среди
которых:
name — имя файлаtype — MIME-типsize — размер в байтахlastModified — дата последнего измененияИменно size используется для ограничения объёма
загружаемого файла.
В Yup нет встроенного метода вроде maxFileSize, поэтому
используется расширение через mixed().test().
import * as yup fr om "yup";
const schema = yup.object({
file: yup
.mixed()
.required("Файл обязателен")
.test("fileSize", "Файл слишком большой", (value) => {
if (!value) return false;
return value.size <= 5 * 1024 * 1024;
}),
});
В данном примере ограничение установлено на 5 MB. Проверка
выполняется напрямую через доступ к свойству size.
При использовании @hookform/resolvers/yup схема
подключается как единый валидатор формы.
import { useForm } fr om "react-hook-form";
import { yupResolver } fr om "@hookform/resolvers/yup";
import * as yup from "yup";
const schema = yup.object({
file: yup
.mixed()
.required("Файл обязателен")
.test("fileSize", "Максимальный размер 2MB", (value) => {
return value && value.size <= 2 * 1024 * 1024;
}),
});
function UploadForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const onSub mit = (data) => {
console.log(data.file);
};
return (
<form onSub mit={handleSubmit(onSubmit)}>
<input type="file" {...register("file")} />
{errors.file && <p>{errors.file.message}</p>}
<button type="submit">Отправить</button>
</form>
);
}
В этом сценарии YupResolver преобразует результат схемы
Yup в формат ошибок, понятный react-hook-form, обеспечивая
единый поток валидации.
При множественной загрузке input[type="file"] возвращает
FileList, который не является массивом, но может быть
обработан как итерируемая структура. В этом случае проверка размера
должна учитывать каждый файл отдельно.
const schema = yup.object({
files: yup
.mixed()
.test("fileSize", "Один из файлов превышает лимит 3MB", (value) => {
if (!value) return false;
const filesArray = Array.from(value);
return filesArray.every((file) => file.size <= 3 * 1024 * 1024);
}),
});
Здесь используется преобразование Array.from,
позволяющее применять стандартные методы массива.
При большом количестве форм целесообразно вынести проверку размера в отдельную функцию, чтобы избежать дублирования логики.
const maxFileSize = (lim it) =>
yup
.mixed()
.test(
"fileSize",
`Файл превышает ${lim it / (1024 * 1024)}MB`,
(value) => {
if (!value) return false;
return value.size <= lim it;
}
);
const schema = yup.object({
avatar: maxFileSize(1 * 1024 * 1024),
document: maxFileSize(10 * 1024 * 1024),
});
Такой подход упрощает сопровождение и обеспечивает единообразие правил валидации.
В реальных интерфейсах загрузка файла часто является необязательной. В этом случае важно не блокировать форму при отсутствии значения, но сохранять проверку при его наличии.
const schema = yup.object({
file: yup
.mixed()
.test("fileSize", "Файл слишком большой", (value) => {
if (!value) return true;
return value.size <= 5 * 1024 * 1024;
}),
});
Ключевой момент заключается в том, что отсутствие файла считается допустимым состоянием.
Ограничение размера часто применяется вместе с проверкой MIME-типа, что позволяет формировать более строгие правила загрузки.
const schema = yup.object({
file: yup
.mixed()
.test("fileType", "Неподдерживаемый формат", (value) => {
if (!value) return false;
return ["image/jpeg", "image/png"].includes(value.type);
})
.test("fileSize", "Файл больше 4MB", (value) => {
if (!value) return false;
return value.size <= 4 * 1024 * 1024;
}),
});
Каждый test выполняется последовательно, и ошибка
возвращается по первому несоответствию.
Хотя YupResolver обеспечивает клиентскую проверку, ограничения размера файла должны дублироваться на сервере. Причина заключается в том, что клиентская валидация не является защитным механизмом, а лишь улучшает пользовательский опыт.
На серверной стороне аналогичная проверка обычно реализуется через
middleware или встроенные ограничения загрузчика (например,
multer в Node.js):
const upload = multer({
limits: {
fileSize: 5 * 1024 * 1024,
},
});
Согласованность лимитов между клиентом и сервером предотвращает расхождения в поведении системы.
Yup позволяет гибко формировать сообщения об ошибках в зависимости от контекста. Это особенно важно при работе с файлами разного назначения.
const schema = yup.object({
file: yup
.mixed()
.test("fileSize", (value) => {
if (!value) return "Файл не выбран";
if (value.size > 2 * 1024 * 1024) {
return "Размер файла не должен превышать 2MB";
}
return true;
}),
});
Такой вариант позволяет динамически возвращать строку ошибки вместо статического сообщения.
При использовании drag-and-drop компонентов структура данных остаётся
аналогичной FileList, но часто дополнительно нормализуется
до массива файлов. В этом случае проверка размера становится частью
более широкой схемы нормализации данных.
const schema = yup.object({
files: yup
.array()
.of(
yup.mixed().test("fileSize", "Файл превышает лимит", (file) => {
return file && file.size <= 3 * 1024 * 1024;
})
),
});
Такая структура обеспечивает предсказуемость при работе с кастомными загрузчиками.
При большом количестве файловых полей имеет смысл минимизировать повторяющиеся вычисления лимитов и использовать константы:
const LIMIT_5MB = 5 * 1024 * 1024;
const schema = yup.object({
avatar: yup.mixed().test("fileSize", "Лимит 5MB", (file) => {
return file ? file.size <= LIMIT_5MB : false;
}),
attachment: yup.mixed().test("fileSize", "Лимит 5MB", (file) => {
return file ? file.size <= LIMIT_5MB : false;
}),
});
Это снижает вероятность расхождений между полями и упрощает поддержку.
Хотя Yup поддерживает асинхронные проверки через
test().then, для проверки размера файла это не требуется,
поскольку операция является синхронной и не зависит от внешних
источников данных. Однако архитектурно важно учитывать, что
YupResolver может обрабатывать асинхронные схемы, что
позволяет расширять логику при необходимости введения удалённых
проверок, например анализа файла перед загрузкой.