0Pricing
React Academy · Урок

Типобезопасные формы и контракты ответов API

Используйте Zod для вывода типов TypeScript из схем и валидации данных форм и ответов API.

«Типобезопасные формы и контракты ответов API» — бесплатный урок React Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Почему типобезопасные структуры данных важны

Формы и ответы API — это границы, через которые в приложение поступают данные из ненадёжных источников. Zod позволяет определять схемы, которые одновременно проверяют данные во время выполнения и выводят типы TypeScript.

Основы схем Zod

Определяйте схемы с помощью гибкого API Zod. Используйте z.infer<typeof schema>, чтобы извлечь тип TypeScript.

import { z } from 'zod';

const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(0).max(150).optional(),
  role: z.enum(['admin', 'user', 'guest']),
});

type User = z.infer<typeof UserSchema>;
// { id: string; name: string; email: string; age?: number; role: 'admin'|'user'|'guest' }

React Hook Form с разрешателем Zod

Интегрируйте схемы Zod с React Hook Form для типобезопасной проверки форм — TypeScript знает структуру данных формы и ошибок.

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const LoginSchema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'At least 8 characters'),
});
type LoginData = z.infer<typeof LoginSchema>;

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<LoginData>({
    resolver: zodResolver(LoginSchema),
  });

  const onSubmit = (data: LoginData) => {
    // data is LoginData — fully typed, already validated
  };
}

Проверка ответов API

Разбирайте ответы API с помощью Zod, чтобы обнаруживать несоответствия структуры на границе приложения. Если API возвращает неожиданные данные, вы получите подробную ошибку вместо сбоя во время выполнения глубоко внутри компонента.

async function fetchUser(id: string): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  const json = await res.json();
  return UserSchema.parse(json); // throws ZodError if shape is wrong
}

Безопасный разбор с safeParse

Используйте schema.safeParse(), чтобы получить объект результата вместо исключения, — это особенно удобно для проверки форм, когда нужно показать ошибки пользователю.

const result = UserSchema.safeParse(formData);
if (!result.success) {
  const errors = result.error.flatten().fieldErrors;
  // { name: ['Must be at least 1 character'], email: ['Invalid email'] }
  return errors;
}
const user = result.data; // User — fully typed

Дискриминированные объединения с Zod

Используйте z.discriminatedUnion, чтобы описывать ответы API с разной структурой в зависимости от признака успешного выполнения или ошибки.

const ApiResponse = z.discriminatedUnion('ok', [
  z.object({ ok: z.literal(true), data: UserSchema }),
  z.object({ ok: z.literal(false), error: z.string(), code: z.number() }),
]);

type ApiResult = z.infer<typeof ApiResponse>;
// { ok: true; data: User } | { ok: false; error: string; code: number }

Преобразования в Zod

Используйте .transform(), чтобы приводить данные к нужному типу или изменять их структуру во время разбора — например, преобразовывать строку с датой в объект Date.

const DateSchema = z.string().transform(s => new Date(s));
// Input: '2024-01-15' → Output: Date object

const EventSchema = z.object({
  title: z.string(),
  date: z.string().pipe(z.coerce.date()),
});
type Event = z.infer<typeof EventSchema>;
// { title: string; date: Date }

Повторное использование схем

Создавайте схемы для создания и обновления на основе базовой схемы, чтобы избежать дублирования.

const UserSchema = z.object({ name: z.string(), email: z.string().email() });

// For creation: add password
const CreateUserSchema = UserSchema.extend({ password: z.string().min(8) });

// For update: all fields optional
const UpdateUserSchema = UserSchema.partial();

type CreateUser = z.infer<typeof CreateUserSchema>;
type UpdateUser = z.infer<typeof UpdateUserSchema>;

Серверное действие с Zod

Проверяйте данные формы в серверном действии Next.js с помощью Zod до обращения к базе данных.

async function createPost(formData: FormData) {
  'use server';
  const schema = z.object({ title: z.string().min(3), body: z.string().min(10) });
  const result = schema.safeParse(Object.fromEntries(formData));
  if (!result.success) return { errors: result.error.flatten().fieldErrors };
  await db.post.create({ data: result.data });
  revalidatePath('/blog');
  redirect('/blog');
}

Общие схемы для фронтенда и бэкенда

Экспортируйте схемы Zod из общего пакета, чтобы фронтенд и бэкенд использовали одну и ту же логику проверки — одна схема служит единым источником истины.

// packages/schemas/src/user.ts
export const CreateUserSchema = z.object({ ... });
export type CreateUser = z.infer<typeof CreateUserSchema>;

// Frontend imports:
import { CreateUserSchema, CreateUser } from '@company/schemas';
// Backend imports:
import { CreateUserSchema } from '@company/schemas';

Сообщения об ошибках Zod

Настраивайте сообщения об ошибках для каждого поля, чтобы улучшить взаимодействие с пользователем: Zod автоматически передаёт их форме для отображения ошибок через средство разрешения.

const RegistrationSchema = z.object({
  username: z.string()
    .min(3, 'Username must be at least 3 characters')
    .max(20, 'Username cannot exceed 20 characters')
    .regex(/^[a-z0-9_]+$/, 'Only lowercase letters, numbers, and underscores'),
});

Быстрая проверка

Что предоставляет z.infer в TypeScript?

Итоги

Определяйте схемы Zod один раз и используйте z.infer, чтобы выводить типы TypeScript. Применяйте zodResolver в React Hook Form для проверки с безопасной типизацией. Проверяйте ответы API с помощью Zod на границе системы, используйте safeParse для ошибок, отображаемых пользователю, и делитесь схемами между фронтендом и бэкендом через общий пакет.

Часто задаваемые вопросы

Урок «Типобезопасные формы и контракты ответов API» бесплатный?

Да — полный текст урока «Типобезопасные формы и контракты ответов API» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Типобезопасные формы и контракты ответов API»?

Используйте Zod для вывода типов TypeScript из схем и валидации данных форм и ответов API. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Типобезопасные формы и контракты ответов API»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Размеченные объединения для вариантов компонентов
  2. Условные и отображаемые типы в React
  3. Полиморфные компоненты со свойством 'as'
  4. Типобезопасные формы и контракты ответов API
← Назад к React Academy