Валидация данных в TypeScript: Zod, Yup и другие инструменты

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Валидация данных в TypeScript: обзор инструментов и практик

В современной веб-разработке на TypeScript одной из ключевых задач является обеспечение целостности данных. Даже при строгой статической типизации TypeScript не может гарантировать, что данные, пришедшие из внешнего мира (API, формы, localStorage), соответствуют ожидаемому формату. Здесь на помощь приходит runtime-валидация — проверка данных во время выполнения программы. В этой статье мы рассмотрим три популярные библиотеки: Zod, Yup и Joi, сравним их подходы и покажем, как интегрировать валидацию в TypeScript-проект.

Почему недостаточно простых типов TypeScript?

TypeScript проверяет типы на этапе компиляции, но в рантайме все аннотации стираются. Это означает, что:

  • Данные от пользователя могут содержать лишние поля или отсутствовать обязательные
  • Числа могут прийти в виде строк
  • Объекты могут быть null или undefined

Библиотеки валидации решают эту проблему, предоставляя схемы, которые работают и как проверка, и как вывод типов.

1. Zod — современный стандарт

Zod — самая популярная библиотека для валидации в TypeScript. Её главное преимущество — автоматический вывод TypeScript-типов из схем.

Установка

npm install zod

Пример базовой схемы

import { z } from 'zod';

const UserSchema = z.object({
  id: z.number().positive(),
  name: z.string().min(2).max(50),
  email: z.string().email(),
  age: z.number().int().min(18).optional(),
});

// Вывод типа: { id: number; name: string; email: string; age?: number }
type User = z.infer<typeof UserSchema>;

// Валидация
const result = UserSchema.safeParse(inputData);
if (!result.success) {
  console.error(result.error.errors);
} else {
  // result.data — корректные данные с типом User
  processUser(result.data);
}

Продвинутые возможности

  • Трансформация: z.string().transform(val => val.trim())
  • Дискриминированные объединения: z.discriminatedUnion('type', [...])
  • Рекурсивные схемы: z.lazy(() => NodeSchema)
  • Кастомные ошибки: z.string().refine(val => !val.includes('bad'), 'Нельзя использовать слово bad')

2. Yup — проверенный временем инструмент

Yup — библиотека с богатой историей, изначально созданная для валидации форм. Она отлично интегрируется с Formik и React Hook Form.

Установка

npm install yup

Пример схемы

import * as yup from 'yup';

const productSchema = yup.object({
  title: yup.string().required('Название обязательно').min(3),
  price: yup.number().positive('Цена должна быть положительной').required(),
  inStock: yup.boolean().default(true),
});

type Product = yup.InferType<typeof productSchema>;

// Валидация
productSchema.validate(inputData, { abortEarly: false })
  .then(validData => console.log(validData))
  .catch(err => console.error(err.errors));

Особенности Yup

  • Поддержка условной валидации: .when('field', ...)
  • Встроенные сообщения об ошибках на русском (при настройке локали)
  • Простая работа с вложенными объектами и массивами
  • Методы cast() и transform() для приведения типов

3. Joi — мощный, но более тяжелый

Joi — легендарная библиотека из экосистемы Node.js (Hapi.js). Она предоставляет максимальную гибкость, но не имеет встроенной интеграции с TypeScript (требует ручного определения типов).

Установка

npm install joi @types/joi

Пример схемы

import Joi from 'joi';

const configSchema = Joi.object({
  port: Joi.number().port().required(),
  dbUrl: Joi.string().uri().required(),
  env: Joi.string().valid('dev', 'prod', 'test').default('dev'),
});

const { error, value } = configSchema.validate(inputConfig);
if (error) {
  throw new Error(`Config validation failed: ${error.message}`);
}
// value — валидные данные

Когда выбирать Joi?

Рекомендаций