webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
Формы · Урок 3 из 4

Валидация с Zod

Схемы, safeParse, coerce для FormData, ошибки по полям, одна схема на клиенте и сервере.

Обновлено

Что такое валидация через схему

Данные, которые попадают в приложение (формы, query-параметры, ответы API, JSON), относятся к типу «не знаю, что это» — unknown. Валидация проверяет, что у них ожидаемая форма и правила, до того как их использовать.

Схема один раз описывает форму данных в виде объекта. Из неё вы получаете три вещи:

  1. валидацию во время выполнения (в браузере и на сервере);
  2. сообщения об ошибках по полям;
  3. тип TypeScript, выведенный автоматически, — писать его вручную больше не нужно.

Zod — стандартная библиотека для этого в экосистеме TypeScript.

Схема

import { z } from 'zod'

export const signupSchema = z.object({
  name: z.string().trim().min(2, 'Слишком короткое имя'),
  email: z.email('Неверный email'),
  age: z.coerce.number().int().min(16, 'Не младше 16 лет'),
  password: z.string().min(8, 'Минимум 8 символов'),
  terms: z.literal('on', 'Нужно принять условия'),
})

export type SignupInput = z.infer<typeof signupSchema>
// { name: string; email: string; age: number; password: string; terms: 'on' }

Базовые типы — и что они решают

Схема Проверяет Заметка
z.string(), z.number(), z.boolean() тип
z.email(), z.url(), z.uuid() форматы строк в Zod 4 они на верхнем уровне; z.string().email() устарел
.min(), .max(), .regex() правила принимают сообщение вторым аргументом
.trim(), .toLowerCase() преобразуют значение результат уже очищен
z.coerce.number() превращает '42' → 42 до проверки необходимо для FormData (там всё строки)
z.enum(['admin', 'editor']) одно из значений
.optional(), .nullable(), .default(x) отсутствующие значения
z.array(schema), z.object({...}) коллекции, вложенные объекты

parse или safeParse

schema.parse(data) schema.safeParse(data)
Верные данные возвращает данные { success: true, data }
Неверные данные бросает ZodError { success: false, error } — не бросает
Когда данные, которые обязаны быть верными (конфиг, env) — ошибка = баг ввод пользователя — ошибки нормальны
const result = signupSchema.safeParse(Object.fromEntries(formData))
if (!result.success) {
  return { errors: z.flattenError(result.error).fieldErrors }
  // { email: ['Неверный email'], age: ['Не младше 16 лет'] }
}
await createUser(result.data)          // типизировано, очищено, преобразовано
Форматирование ошибок Результат Когда
z.flattenError(error) { formErrors: [], fieldErrors: { email: [...] } } простые формы (один уровень)
z.treeifyError(error) дерево по форме схемы вложенные объекты, списки

Правила для нескольких полей

const schema = z
  .object({ password: z.string().min(8), confirm: z.string() })
  .refine(d => d.password === d.confirm, { message: 'Пароли не совпадают', path: ['confirm'] })

path ставит ошибку на нужное поле.

Одна схема — два места

Главный плюс: одна и та же схема на клиенте (быстрая обратная связь в форме) и на сервере (безопасность).

  • src/
    • features/
      • signup/
        • model/
          • signup-schema.tsсхема Zod + выведенный тип
        • ui/
          • signup-form.tsxuseForm({ resolver: zodResolver(signupSchema) })
        • api/
          • signup-action.ts'use server' → signupSchema.safeParse(...)

Клиентскую валидацию можно обойти в любой момент. Значение имеет серверная.

Альтернативы

Библиотека Почему выбрать
Zod стандарт, огромная экосистема, отличные типы
Valibot модульный API, гораздо меньший бандл для клиента
ArkType синтаксис, близкий к TypeScript, очень быстрый

Все три реализуют Standard Schema — библиотеки форм принимают их одинаково.

Коротко

  • Схема = валидация + сообщения + TS-тип, написанные один раз.
  • safeParse для ввода пользователя; z.coerce для FormData; z.flattenError для ошибок по полям.
  • Одна схема на клиенте и сервере; решает сервер.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.