Zod in React/React Native

abdul ahad
5 min read4 days ago

--

Photo by Lautaro Andreani on Unsplash

Zod is a TypeScript-first schema validation library that helps developers define and validate the shape of data, ensuring that it adheres to the expected format. In the context of a React application, Zod is used to create schemas that define the structure of data, such as form inputs or API responses. Zod allows for strict type validation, and its close integration with TypeScript makes it possible to infer types directly from schemas, making it easier to maintain type safety across your application.

With Zod, you can define individual properties in a schema (e.g., strings, numbers, booleans) and validate them by parsing data against the schema. If the data doesn’t meet the specified criteria, Zod throws detailed errors or allows for safe parsing, returning a success/failure result for handling. This is particularly useful for validating forms, API request payloads, or environment variables.

Here’s a detailed breakdown of key concepts and examples:

1. Creating Schemas

A schema in Zod defines the structure of your data. You specify what type each field is supposed to have (e.g., string, number, array, etc.).

Example: Creating a Simple Schema

import { z } from 'zod';

const userSchema = z.object({
firstName: z.string(),
age: z.number(),
email: z.string().email(),
});

// Validating data
const userData = {
firstName: 'John',
age: 25,
email: 'john@example.com',
};

userSchema.parse(userData); // If the data is valid, it passes; otherwise, throws an error.

In this example:

  • z.string() specifies that firstName and email must be strings.
  • .email() adds a check to ensure the email string is in a valid email format.
  • z.number() ensures that age is a number.

If any of these fields are missing or of the wrong type, Zod throws an error.

2. Validating Data

Once you have a schema, you can validate data by calling parse on your schema. If the data doesn't conform, Zod throws an error.

Example: Handling Errors

try {
userSchema.parse({
firstName: 'John',
age: '25', // Wrong data type
email: 'john@example',
});
} catch (e) {
console.log(e.errors);
}
// Output: Error: expected number, got string

3. Safe Parsing

If you want to avoid exceptions and handle validation failures gracefully, use safeParse, which returns an object with a success property.

Example: Safe Parsing

const result = userSchema.safeParse({
firstName: 'John',
age: 25,
email: 'not-an-email',
});

if (!result.success) {
console.log(result.error.errors); // Handle the error
} else {
console.log(result.data); // Process valid data
}

4. Optional and Nullable Fields

Zod allows fields to be optional or nullable, meaning they can be absent or null, respectively.

Example: Optional and Nullable Fields

const schema = z.object({
middleName: z.string().optional(), // Field is optional
nickname: z.string().nullable(), // Field can be null
});

schema.parse({
middleName: 'Lee', // This can be omitted, and no error will be thrown.
nickname: null, // Null is accepted here.
});

5. Chaining Modifiers

Zod allows you to chain methods to add extra validation rules. You can chain things like .min() or .max() for numeric or array fields, or even .email() for strings.

Example: Adding Constraints

const schema = z.object({
age: z.number().min(18).max(60), // Age must be between 18 and 60
friends: z.array(z.string()).max(5), // Max 5 friends
});

schema.parse({
age: 25,
friends: ['Alice', 'Bob'],
});

6. Array and Object Validation

You can validate arrays and nested objects within a schema.

Example: Validating Arrays and Nested Objects

const schema = z.object({
name: z.string(),
friends: z.array(z.object({
name: z.string(),
age: z.number(),
})),
});

schema.parse({
name: 'John',
friends: [
{ name: 'Alice', age: 24 },
{ name: 'Bob', age: 30 },
],
});

In this example, the friends field is an array of objects where each object has a name and age.

7. Inferring Types with TypeScript

Zod allows you to infer TypeScript types from your schema, ensuring your data is fully typed throughout your application.

Example: Type Inference

const userSchema = z.object({
firstName: z.string(),
age: z.number(),
});

type User = z.infer<typeof userSchema>;

const user: User = {
firstName: 'John',
age: 25,
};

Here, the User type is automatically generated from the Zod schema, and you can use it throughout your codebase for type safety.

8. Zod with Forms (React Hook Form Example)

One common use of Zod is validating forms in React. You can integrate Zod with form libraries like React Hook Form to automatically validate form data.

Example: React Hook Form Integration

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const formSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email"),
});

export default function MyForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(formSchema),
});

const onSubmit = (data) => {
console.log(data);
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} />
<p>{errors.name?.message}</p>

<input {...register("email")} />
<p>{errors.email?.message}</p>

<button type="submit">Submit</button>
</form>
);
}

In this example, Zod handles validation, and React Hook Form integrates it into the form submission process, displaying error messages if validation fails.

9. Validating Environment Variables

You can use Zod to validate environment variables to ensure your application has all the required settings at runtime.

Example: Environment Variable Validation

import { z } from 'zod';

const envSchema = z.object({
SECRET_KEY: z.string(),
PORT: z.string().regex(/^\d+$/, "Must be a number"),
});

const env = envSchema.parse(process.env);
console.log(env.SECRET_KEY, env.PORT);

Here, Zod ensures that the SECRET_KEY and PORT environment variables are present and valid. If they’re not, Zod will throw an error, and the application won’t run without proper configuration.

10. Error Messages

Zod allows you to customize error messages for more detailed validation feedback.

Example: Custom Error Messages

const schema = z.object({
age: z.number().min(18, "You must be at least 18 years old"),
});

try {
schema.parse({ age: 16 });
} catch (e) {
console.log(e.errors); // Output: You must be at least 18 years old
}

11. Safe Error Handling

When using .safeParse(), instead of throwing errors, Zod returns a result object with success or failure information, allowing you to handle errors more gracefully.

Example: Safe Parsing with Error Handling

const result = schema.safeParse({ age: 16 });

if (!result.success) {
console.log(result.error.errors); // Output: Custom error message
}

Zod’s flexibility and integration with TypeScript make it an ideal tool for validating data in a wide range of contexts, from form inputs to API requests and beyond. It simplifies validation while keeping your code fully type-safe, helping prevent runtime errors.

see part 2 for Zod with Hook Forms Example.

--

--

abdul ahad

A software developer dreaming to reach the top and also passionate about sports and language learning