Валидация данных в 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 — валидные данные