При работе с формами в JavaScript значения, приходящие от
пользователя, почти всегда представлены строками. Даже числовые поля
HTML-форм возвращают "12.34" вместо 12.34. В
контексте валидации с использованием Yup важной задачей становится не
только проверка корректности числа, но и его приведение к нужному виду,
включая округление.
Округление в схемах Yup не является отдельной встроенной операцией,
однако оно легко реализуется через механизм преобразования
(transform), который позволяет изменять входное значение до
применения правил валидации.
Любая логика округления должна начинаться с нормализации типа данных. Типичный сценарий — преобразование строки в число:
import * as Yup from 'yup';
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
if (typeof originalValue === 'string') {
return Number(originalValue.replace(',', '.'));
}
return value;
})
});
Здесь учитывается частая проблема локализации, когда десятичный разделитель может быть запятой.
После приведения значения к числу можно применить стандартные функции
JavaScript для округления. В Yup это делается внутри
transform, так как сам валидатор не изменяет значение
автоматически.
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Math.round(parsed);
})
});
В этом случае:
12.7 → 1312.2 → 12Часто требуется не целое число, а округление до 2 знаков после запятой, например для денежных значений.
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Math.round(parsed * 100) / 100;
})
});
Механизм основан на масштабировании числа:
Альтернативный способ — применение toFixed, однако важно
помнить, что он возвращает строку, поэтому требуется дополнительное
преобразование:
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Number(parsed.toFixed(2));
})
});
Этот вариант часто используется, когда важно строгое форматирование до заданной точности.
Помимо стандартного математического округления, часто требуется управление направлением округления:
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Math.floor(parsed * 100) / 100;
})
});
const schema = Yup.object({
price: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Math.ceil(parsed * 100) / 100;
})
});
Иногда округление должно применяться только при успешной валидации, чтобы избежать потери точности при ошибочных данных:
const schema = Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
return isNaN(parsed) ? value : parsed;
})
.test('rounding', function (value) {
if (typeof value !== 'number') return true;
const rounded = Math.round(value * 100) / 100;
if (value !== rounded) {
return this.createError({
message: 'Число должно быть округлено до 2 знаков'
});
}
return true;
});
Округлённые значения часто сразу проходят дополнительные проверки:
const schema = Yup.object({
rating: Yup.number()
.transform((value, originalValue) => {
const parsed = Number(originalValue);
return isNaN(parsed) ? value : Math.round(parsed * 10) / 10;
})
.min(0)
.max(5)
});
Здесь значение:
Механизм transform в Yup имеет несколько важных
особенностей:
test, min,
max)cast()strict(false)Это делает его основным инструментом для реализации округления.
Использование схемы для округления позволяет централизовать правила обработки чисел:
const moneySchema = Yup.number().transform((value, originalValue) => {
const parsed = Number(originalValue);
if (isNaN(parsed)) return value;
return Math.round(parsed * 100) / 100;
});
Такая схема становится переиспользуемой и обеспечивает единообразие представления чисел во всей системе.
Особое внимание требуется случаям:
""nullundefined" "transform((value, originalValue) => {
if (originalValue == null || originalValue === '') {
return value;
}
const parsed = Number(originalValue);
return isNaN(parsed) ? value : Math.round(parsed * 100) / 100;
})
Игнорирование этих случаев может приводить к некорректной интерпретации данных.
В рамках Yup округление всегда реализуется через преобразование входного значения перед применением правил проверки. Такой подход обеспечивает:
Механизм transform выступает центральным инструментом,
позволяющим встроить арифметические преобразования непосредственно в
схему валидации.