logo
Basic Utils
Home

How to Learn Zod: Complete Guide to Zod Schema, Validation, Transformations, and More

In the world of TypeScript and JavaScript development, data validation and schema management are crucial aspects of creating robust applications. One library that has been gaining attention for its powerful yet intuitive approach to schema validation is Zod. This tutorial will walk you through everything you need to know about Zod, from its basics to advanced features, with practical examples and comparisons.

What is Zod?

Zod is a TypeScript-first schema declaration and validation library. It allows you to define schemas for your data and validate that your data conforms to these schemas. Zod provides a fluent API to build and validate schemas easily and integrates well with TypeScript’s static type checking.

How Does Zod Work?

Zod works by allowing you to define a schema for your data and then use that schema to validate data at runtime. Here’s a basic example to illustrate how Zod works:


import { z } from 'zod';

// Define a Zod schema
const userSchema = z.object({
  name: z.string(),
  age: z.number().int().positive(),
});

// Validate data against the schema
const result = userSchema.safeParse({ name: 'Alice', age: 30 });
console.log(result); // { success: true, data: { name: 'Alice', age: 30 } }

const invalidResult = userSchema.safeParse({ name: 'Alice', age: -5 });
console.log(invalidResult.error.format()); // Error due to age being negative
                

Why Use Zod Instead of TypeScript?

TypeScript provides static type checking, which is great for development-time type safety. However, it doesn’t handle runtime validation. This is where Zod comes in. While TypeScript ensures that your types are correct at compile time, Zod ensures that your data is valid at runtime.

Zod vs TypeScript

  • TypeScript

    Ensures type safety at compile time. Types are erased at runtime, so there's no built-in mechanism to enforce data validity during execution.

  • Zod

    Provides runtime validation to ensure that data adheres to the specified schema. This validation happens during execution and complements TypeScript’s compile-time checks.

Using Zod alongside TypeScript allows you to validate data thoroughly, combining the best of both worlds.

Zod Schema

Zod schemas define the shape and constraints of your data. They are highly customizable and can be composed to handle complex data structures.

Basic Schema Example


import { z } from 'zod';

// Define a basic schema
const schema = z.object({
  name: z.string(),
  age: z.number(),
});

// Validate data
const validationResult = schema.safeParse({ name: 'Bob', age: 25 });
console.log(validationResult); // { success: true, data: { name: 'Bob', age: 25 } }
                

Schema with Nested Objects


const nestedSchema = z.object({
  user: z.object({
    name: z.string(),
    age: z.number(),
  }),
  address: z.object({
    city: z.string(),
    postalCode: z.string(),
  }),
});

const nestedResult = nestedSchema.safeParse({
  user: { name: 'Alice', age: 30 },
  address: { city: 'Wonderland', postalCode: '12345' },
});
console.log(nestedResult); // { success: true, data: ... }
                

Zod Validation

Zod validation involves checking if the data conforms to the defined schema. Zod provides various methods to handle different validation scenarios.

Required Fields


const optionalSchema = z.object({
  name: z.string().optional(),
  age: z.number().optional(),
});

const resultWithOptionalFields = optionalSchema.safeParse({ name: 'John' });
console.log(resultWithOptionalFields); // { success: true, data: { name: 'John', age: undefined } }
                

Regex Validation


import { z } from 'zod';

const schema = z.string().regex(/^[a-zA-Z0-9]+$/, 'Invalid input');

// Example usage
try {
  schema.parse('valid123'); // Passes validation
  schema.parse('invalid!@#'); // Throws error: Invalid input
} catch (e) {
  console.error(e.errors); // Logs validation error
}
        

Zod Transform

Transformations in Zod allow you to modify data as it is being validated. This is useful for data normalization or preprocessing.

Basic Transform Example


const transformSchema = z.string().transform((val) => val.toUpperCase());

const transformedResult = transformSchema.safeParse('hello');
console.log(transformedResult); // { success: true, data: 'HELLO' }
                

Transform with Object Schema


const userSchemaWithTransform = z.object({
  name: z.string().transform((val) => val.trim()),
  age: z.number(),
});

const transformedUserResult = userSchemaWithTransform.safeParse({ name: ' Alice ', age: 25 });
console.log(transformedUserResult); // { success: true, data: { name: 'Alice', age: 25 } }
                

Zod Refine

The refine method in Zod is used for custom validation logic that goes beyond the built-in constraints.

Refine Example


const ageSchema = z.number().refine((val) => val >= 18, {
  message: 'Age must be at least 18',
});

const validAge = ageSchema.safeParse(25);
console.log(validAge); // { success: true, data: 25 }

const invalidAge = ageSchema.safeParse(16);
console.log(invalidAge.error.format()); // Error due to age being less than 18
                

Zod Preprocess

The preprocess method allows you to modify the input data before it is validated.

Preprocess Example


const preprocessSchema = z.preprocess(
  (input) => (typeof input === 'string' ? parseInt(input, 10) : input),
  z.number()
);

const processedResult = preprocessSchema.safeParse('42');
console.log(processedResult); // { success: true, data: 42 }

const invalidResult = preprocessSchema.safeParse('not a number');
console.log(invalidResult.error.format()); // Error due to invalid number
                

Zod Examples

Here are more practical examples of using Zod in various scenarios:

Zod Enum Example


const ColorEnum = z.enum(['Red', 'Green', 'Blue']);

const colorResult = ColorEnum.safeParse('Red');
console.log(colorResult); // { success: true, data: 'Red' }

const invalidColorResult = ColorEnum.safeParse('Yellow');
console.log(invalidColorResult.error.format()); // Error due to 'Yellow' not being in the enum
                

Zod Form Example


const formSchema = z.object({
  username: z.string().min(3, 'Username must be at least 3 characters long'),
  password: z.string().min(6, 'Password must be at least 6 characters long'),
});

const formData = { username: 'user', password: 'pass123' };
const formResult = formSchema.safeParse(formData);
console.log(formResult); // { success: true, data: { ... } }
                

Comparison: What is Faster Than Zod?

When it comes to performance, different libraries and methods have varying speeds. Zod is known for its efficiency and ease of use, but there are other libraries and techniques that might be faster depending on your needs.

Joi: Another popular validation library that is mature and feature-rich but can be slower in some cases compared to Zod.

Yup: Provides a similar feature set but might have different performance characteristics.

Custom Validators: Writing your own validation logic can sometimes be more performant if you have very specific requirements.

Conclusion

Zod is a powerful tool for handling schema validation in TypeScript applications. It offers a clear, concise API for defining schemas, validating data, and performing transformations. Whether you’re using Zod for basic data validation or complex scenarios involving enums and custom logic, it provides a robust solution that complements TypeScript’s type system.

By understanding and utilizing Zod’s features—such as schema definitions, validation methods, transformations, refinements, and preprocessors—you can enhance your application’s data integrity and maintainability.

Feel free to experiment with the examples provided and integrate Zod into your projects to improve data validation and overall application quality. Happy coding!

Sources

  • Zod Documentation

    https://zod.dev/docs

  • TypeScript Handbook

    https://www.typescriptlang.org/docs/handbook/enum.html

  • Zod GitHub Repository

    https://github.com/colinhacks/zod

  • TypeScript Official Documentation

    https://www.typescriptlang.org/docs/

logo
Basic Utils

simplify and inspire technology

©2024, basicutils.com