Валидация данных в TypeScript: библиотеки Zod, Yup и io-ts

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

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

Начать курс

Валидация данных в TypeScript: обзор библиотек Zod, Yup и io-ts

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

В этой статье мы рассмотрим три популярные библиотеки для валидации данных в TypeScript: Zod, Yup и io-ts. Вы узнаете, как они работают, в чём их различия и как выбрать подходящую для вашего проекта.

Зачем нужна валидация данных в TypeScript?

Представьте, что вы пишете приложение, которое получает данные от пользователя через форму:

interface UserInput {
  name: string;
  age: number;
  email: string;
}

function processUserInput(input: UserInput) {
  console.log(input.name.toUpperCase());
}

В TypeScript этот код скомпилируется, даже если в рантайме input.name окажется undefined или числом. Это приведёт к ошибке, которую сложно отловить. Библиотеки валидации позволяют гарантировать, что данные соответствуют ожидаемой схеме, и предоставляют понятные сообщения об ошибках.

Zod — современная и быстрая библиотека

Zod — это библиотека для декларативной валидации и вывода типов. Она создана специально для TypeScript и предлагает лаконичный API.

Установка:

npm install zod

Пример использования:

import { z } from 'zod';

// Определяем схему валидации
const UserSchema = z.object({
  name: z.string().min(2, "Имя должно содержать минимум 2 символа"),
  age: z.number().int().positive("Возраст должен быть положительным числом"),
  email: z.string().email("Некорректный email"),
});

// Вывод типа на основе схемы
type User = z.infer<typeof UserSchema>;

// Валидация данных
const result = UserSchema.safeParse({
  name: "Анна",
  age: 25,
  email: "anna@example.com",
});

if (result.success) {
  // result.data имеет тип User
  console.log(result.data.name);
} else {
  // result.error содержит подробную информацию об ошибках
  console.error(result.error.format());
}

Zod поддерживает сложные структуры: вложенные объекты, массивы, объединения, discriminated unions. Он также умеет трансформировать данные (например, приводить строки к числам).

Yup — популярная библиотека из экосистемы React

Yup — это библиотека для валидации схем, которая широко используется вместе с Formik в React-приложениях. Она имеет схожий с Zod API, но появилась раньше.

Установка:

npm install yup

Пример использования:

import * as yup from 'yup';

// Определяем схему
const userSchema = yup.object({
  name: yup.string().min(2, "Имя должно содержать минимум 2 символа").required(),
  age: yup.number().integer().positive().required(),
  email: yup.string().email("Некорректный email").required(),
});

// Валидация с помощью метода validate
userSchema.validate({
  name: "Иван",
  age: 30,
  email: "ivan@example.com",
})
.then(validData => console.log(validData))
.catch(err => console.error(err.errors));

Yup предоставляет удобные методы для валидации форм, поддерживает кастомные сообщения об ошибках и условные правила (when). Однако он менее тесно интегрирован с TypeScript, чем Zod — вывод типов требует дополнительных действий.

io-ts — функциональный подход к валидации

io-ts — это библиотека, основанная на функциональном программировании. Она использует концепцию кодеков (codecs) для преобразования и валидации данных. io-ts особенно популярен в проектах, где используется fp-ts (функциональные монады).

Установка:

npm install io-ts fp-ts

Пример использования:

import * as t from 'io-ts';
import { either } from 'fp-ts';

// Определяем кодек
const UserCodec = t.type({
  name: t.string,
  age: t.Int,
  email: t.string,
});

// Функция для декодирования данных
const decodeUser = (input: unknown) => {
  const result = UserCodec.decode(input);
  if (either.isRight(result)) {
    // result.right содержит валидные данные
    console.log(result.right.name);
  } else {
    // result.left содержит ошибки
    console.error(result.left);
  }
};

decodeUser({ name: "Пётр", age: 28, email: "petr                    

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