Vue
Валидация форм
Форма регистрации начинается с пары if: проверить, что email не пустой и есть @. Через месяц требований десять: длина пароля, совпадение паролей, формат телефона, обязательность согласия, асинхронная проверка занятости логина. Самописные if расползаются по компоненту, типы ошибок никто не гарантирует, а сообщения дублируются. VeeValidate в связке с Zod даёт схему как единый источник правды: одна Zod-схема описывает и валидацию, и типы данных, и форма знает их без единого as.
- Регистрация: Zod-схема описывает email, пароль и подтверждение, VeeValidate показывает ошибки под полями
- Чекаут: одна схема валидирует адрес доставки на клиенте и переиспользуется на сервере
- Форма настроек профиля: типы данных выводятся из схемы, компонент не дублирует интерфейс руками
- Онбординг в SaaS: пошаговая форма, где каждый шаг это часть общей Zod-схемы
- Форма обратной связи: required-поля и формат email описаны декларативно, без россыпи if в обработчике
Предварительные знания
- Двусторонняя привязка v-model на полях формы из предыдущего урока
- Базовый TypeScript: интерфейсы, дженерики, вывод типов
- Понимание идеи схемы данных: описание формы значения и его ограничений
Подходы к валидации
Ручные проверки через if работают на крошечной форме, но плохо масштабируются. Логика валидации размазывается по обработчику, сообщения об ошибках дублируются, а тип объекта ошибок никто не контролирует. Схемный подход разворачивает это: правила описываются декларативно в одном месте, а библиотека формы применяет их и отдаёт типизированные ошибки.
- Ручные if — Каждое правило это код в обработчике. Объект ошибок собирается вручную, его тип не гарантирован, сообщения дублируются при росте формы
- Схема (Zod) + VeeValidate — Правила в одной схеме, типы выводятся из неё, ошибки типизированы. Форма масштабируется добавлением полей в схему, а не кода в обработчик
| Критерий | Ручные if | Схема + VeeValidate |
|---|---|---|
| Источник правил | Разбросан по коду | Единая схема |
| Типы ошибок | Не гарантированы | Выводятся из схемы |
| Переиспользование | Копирование | Импорт схемы |
| Масштабирование | Больше if | Поля в схеме |
Схемный подход не означает отказ от собственных правил. Сложная бизнес-логика выражается через refine и superRefine в Zod, поэтому декларативность не упирается в простые проверки длины и формата.
Чем схемный подход к валидации лучше россыпи ручных if при росте формы?
Zod-схема и вывод типов
Zod описывает форму данных как схему: типы полей, ограничения, сообщения. Из той же схемы метод z.infer выводит TypeScript-тип, поэтому интерфейс не пишут руками и он не рассинхронизируется с правилами. Это устраняет потребность в ручных кастах: тип данных формы выводится из схемы автоматически.
Метод safeParse возвращает результат с дискриминантным полем success. Это и есть type guard: в ветке success === true TypeScript сужает тип к валидным данным, в ветке false доступен типизированный error. Никакого non-null и явного каста не требуется, сужение делает сам компилятор.
Правило проекта без any, без non-null и без явных кастов выполняется здесь естественно: z.infer даёт тип, safeParse даёт сужение через discriminated union. Каст не нужен, потому что типы выводятся из схемы.
Как получить TypeScript-тип данных формы из Zod-схемы без ручного интерфейса?
VeeValidate с Zod-схемой
VeeValidate подключает Zod-схему через адаптер toTypedSchema. useForm принимает типизированную схему и возвращает handleSubmit, errors и состояние формы. useField связывает конкретное поле с v-model и отдаёт его значение и сообщение об ошибке. Типы при этом выводятся из той же схемы.
toTypedSchema это мост между Zod и VeeValidate: он превращает Zod-схему в формат, который понимает VeeValidate, и протягивает выведенные типы в useForm. Дженерик useField<string> задаёт тип значения поля без приведения.
handleSubmit вызывает переданный колбэк только после успешной валидации всей схемы. Поэтому внутри колбэка values уже валидны и типизированы, и проверять их повторно или приводить тип не нужно.
Зачем Zod-схему оборачивают в toTypedSchema перед передачей в useForm?
Вывод типизированных сообщений
Объект errors из useForm типизирован по ключам схемы: errors.email и errors.password существуют, а опечатка errors.emial вызовет ошибку компиляции. Сообщения берутся из схемы, поэтому текст ошибки задаётся один раз в Zod и не дублируется в шаблоне. Так вывод сообщений остаётся типобезопасным.
Поскольку errors типизирован, IDE подсказывает доступные ключи, а несуществующее поле не пройдёт сборку. Это убирает класс багов, где сообщение об ошибке висит на несуществующем поле из-за опечатки и потому никогда не показывается.
| Что | Откуда берётся | Гарантия |
|---|---|---|
| Текст ошибки | message в Zod-схеме | Один источник, не дублируется |
| Ключ поля errors.x | Имена полей схемы | Проверяется компилятором |
| Тип values при сабмите | z.infer схемы | Без any и каста |
Если сообщение об ошибке не показывается, при типизированном errors первым делом проверяют не опечатку в ключе (её поймает компилятор), а совпадает ли path в refine с именем поля в шаблоне.
Какое преимущество даёт типизированный объект errors из useForm?
Связь с другими темами
Урок про декларативную валидацию. Дальше схему применяют к серверным данным и переиспользованию:
- Загрузка данных — Та же Zod-схема валидирует ответ сервера, а не только ввод формы
- VueUse — Тот же принцип: брать проверенные composable-решения вместо ручного кода
Итог
- Самописные if плохо масштабируются: типы ошибок не гарантированы, логика и сообщения дублируются по компоненту
- Zod описывает схему данных декларативно, а z.infer выводит из неё TypeScript-тип без ручного дублирования интерфейса
- VeeValidate с toTypedSchema подключает Zod-схему: useForm и useField дают значения, ошибки и состояние полей
- Ошибки типизированы и берутся из схемы, поэтому компонент не нуждается в any, non-null или явных кастах
- Одна схема переиспользуется на клиенте и сервере, что убирает рассинхрон правил валидации между ними
Связанные уроки
- vue-30-data-fetching — Валидную форму отправляют на сервер, и ответ сервера тоже стоит валидировать той же Zod-схемой
- vue-34-vueuse — И VeeValidate, и VueUse это переиспользование проверенных composable-решений вместо самописного кода