Nullable и optional поля в контексте схем валидации на базе Yup имеют принципиальное различие, которое напрямую влияет на поведение форм, сериализацию данных и результат работы резолвера в связке с YupResolver и React Hook Form.
Внутренне обработка значений разделяется на два независимых состояния отсутствия данных:
undefined — поле не передано вообщеnull — поле передано, но явно пустоеЭта разница становится критичной при построении схем, поскольку:
undefined обычно трактуется как «не заполнено
пользователем»null трактуется как «значение существует, но
отсутствует по смыслу»Валидационные схемы по умолчанию ориентированы на
undefined как признак отсутствия значения, тогда как
null требует явного разрешения через
nullable().
.optional()Опциональность в схемах означает допустимость отсутствия значения в объекте данных.
В Yup опциональность выражается неявно: поле считается опциональным,
если отсутствует требование required().
Типичное поведение:
undefined) — валидноПример схемы:
import * as yup from "yup";
const schema = yup.object({
username: yup.string(),
});
В этом случае username:
Важно, что отсутствие required() не означает
допустимость null.
.nullable()Метод .nullable() изменяет допустимые значения поля,
разрешая null как валидное значение.
const schema = yup.object({
nickname: yup.string().nullable(),
});
Поведение:
undefined — допустимо (если нет
required)null — допустимоКлючевая особенность заключается в том, что null
перестаёт приводиться к ошибке типа.
При использовании трансформаций null часто требует
отдельной обработки:
yup.string().nullable().transform((value, originalValue) =>
originalValue === "" ? null : value
);
Такой подход используется для унификации пустых строк и
null.
.nullable() и отсутствия requiredРазделение логики:
undefined) — управляет наличием
поляnull) — управляет допустимым значениемСравнение поведения:
| Схема | undefined | null | значение |
|---|---|---|---|
string() |
допустимо | ошибка | строка |
string().nullable() |
допустимо | допустимо | строка |
string().required() |
ошибка | ошибка | строка |
string().nullable().required() |
ошибка | ошибка | строка |
Последний случай демонстрирует, что required() сильнее
nullable() и запрещает отсутствие значения в любом
виде.
В связке с форм-менеджером React Hook Form резолвер выполняет преобразование входных данных перед валидацией.
Ключевые моменты:
undefined часто приходит из незаполненных
контроловnull может приходить из кастомных компонентов (select,
datepicker)Следовательно, схема должна явно описывать допустимые состояния.
Пример поведения:
const schema = yup.object({
birthday: yup.date().nullable(),
});
Если компонент возвращает null при очистке поля, без
.nullable() будет получена ошибка несоответствия типа.
При использовании React Hook Form значения по умолчанию задаются
через defaultValues.
Поведение:
defaultValues →
undefinednull → передаётся как значениеЭто влияет на поведение Yup:
undefined игнорируется для optional полейnull требует разрешения через
.nullable()Особенно критично для форм с динамическими полями.
.nullable() и required()Комбинация выглядит противоречивой, но используется для тонкой настройки:
yup.string().nullable().required()
Логика:
required() запрещает undefinednullable() разрешает null на уровне
типаФактический результат:
undefined → ошибка (required)null → часто трактуется как пустое значение и приводит
к ошибке requiredИспользование такой комбинации обычно связано с миграцией схем или
обработкой API, где null приходит как временное
состояние.
yup.string()
Предположение: допустимы null и
undefined
Фактическое поведение:
undefined допустимоnull вызывает ошибкуФормы часто передают:
"" вместо nullnull вместо undefinedБез трансформации схема становится непредсказуемой.
DatePicker и Sel ect часто возвращают null при очистке.
Без .nullable() возникает ошибка несоответствия типов даже
при корректной логике формы.
При проектировании схемы обычно используется следующая логика:
undefined — поле не участвовало в заполненииnull — пользователь явно очистил значениеНа уровне Yup это выражается комбинацией:
.optional() (по умолчанию).nullable() (при необходимости поддержки очистки).transform() (для унификации входных данных)import * as yup fr om "yup";
const schema = yup.object({
name: yup.string().required(),
email: yup.string().email().required(),
phone: yup.string().nullable(),
age: yup.number().nullable().transform((value, originalValue) =>
originalValue === "" ? null : value
),
comment: yup.string(),
});
В данной конфигурации:
name, email — строго обязательные
значенияphone — допускает отсутствие и явный nullage — нормализует пустую строку в nullcomment — полностью опциональное поле без допуска
null