Data Validation in TypeScript: Overview of Tools and Practices
In modern web development with TypeScript, one of the key tasks is ensuring data integrity. Even with strict static typing, TypeScript cannot guarantee that data coming from the outside world (API, forms, localStorage) matches the expected format. This is where runtime validation comes to the rescue — checking data during program execution. In this article, we will look at three popular libraries: Zod, Yup, and Joi, compare their approaches, and show how to integrate validation into a TypeScript project.
Why Are Simple TypeScript Types Not Enough?
TypeScript checks types at compile time, but at runtime all annotations are erased. This means that:
- User data may contain extra fields or lack required ones
- Numbers may come as strings
- Objects may be
nullorundefined
Validation libraries solve this problem by providing schemas that work both as validation and type inference.
1. Zod — The Modern Standard
Zod is the most popular library for validation in TypeScript. Its main advantage is automatic TypeScript type inference from schemas.
Installation
npm install zodBasic Schema Example
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(),});
// Type inference: { id: number; name: string; email: string; age?: number }type User = z.infer<typeof UserSchema>;
// Validationconst result = UserSchema.safeParse(inputData);if (!result.success) { console.error(result.error.errors);} else { // result.data — valid data with type User processUser(result.data);}Advanced Features
- Transformation:
z.string().transform(val => val.trim()) - Discriminated Unions:
z.discriminatedUnion('type', [...]) - Recursive Schemas:
z.lazy(() => NodeSchema) - Custom Errors:
z.string().refine(val => !val.includes('bad'), 'Cannot use the word bad')
2. Yup — A Time-Tested Tool
Yup is a library with a rich history, originally created for form validation. It integrates well with Formik and React Hook Form.
Installation
npm install yupSchema Example
import * as yup from 'yup';
const productSchema = yup.object({ title: yup.string().required('Title is required').min(3), price: yup.number().positive('Price must be positive').required(), inStock: yup.boolean().default(true),});
type Product = yup.InferType<typeof productSchema>;
// ValidationproductSchema.validate(inputData, { abortEarly: false }) .then(validData => console.log(validData)) .catch(err => console.error(err.errors));Yup Features
- Support for conditional validation:
.when('field', ...) - Built-in error messages in Russian (when locale is configured)
- Easy work with nested objects and arrays
cast()andtransform()methods for type coercion
3. Joi — Powerful but Heavier
Joi is a legendary library from the Node.js ecosystem (Hapi.js). It provides maximum flexibility but does not have built-in TypeScript integration (requires manual type definitions).
Installation
npm install joi @types/joi<