# Using Zod with TypeScript: A Guide for Frontend Developers

> Master data validation and schema declaration with Zod TypeScript. Simplify your frontend development workflow and enhance type safety effortlessly.

By Harshal Ranjhani · [HTML version](https://harshalranjhani.in/blog/using-zod-with-typescript-a-guide-for-frontend-developers)

If you're building a frontend application, you're likely working with data. Whether you're fetching data from an API, handling form submissions, or managing state, you need to ensure that the data you're working with is valid. Enter Zod, your new best friend. In this article, we'll explore how to use this powerful library with TypeScript to validate data in your frontend applications.

## What is Zod?

Zod is a TypeScript-first schema declaration and validation library. It allows you to define the shape of your data using a schema and validate that data against that schema. It is designed to be easy to use, type-safe, and performant—making it a great tool for ensuring that the data in your application is valid and consistent. Imagine writing less boilerplate code and letting this library handle the heavy lifting of data validation.

## Installing Zod
### Requirements

- TypeScript 4.5+!

- You must enable `strict` mode in your `tsconfig.json`. This is a best practice for all TypeScript projects.

```json
// tsconfig.json
{
  // ...
  "compilerOptions": {
    // ...
    "strict": true
  }
}
```
To get started, install the library using npm or yarn:

```sh
npm install zod
```
Or if you're using yarn:

```sh
yarn add zod
```
Once installed, you can start importing the library in your TypeScript files and take advantage of its powerful features.

## Understanding Primitives
At the core of the library are the primitive types. These are the basic building blocks that you can use to define the shape of your data. The library provides a range of primitive types, including `string`, `number`, `boolean`, `null`, and `undefined`. You can use these types to define the structure of your data and validate that it conforms to your expectations.

### String
The string type represents a string value. You can use it to validate that a value is a string:

```typescript
import { z } from "zod";

const stringSchema = z.string();
```
You can also enforce various constraints like minimum and maximum lengths, or specific patterns:

```typescript
const usernameSchema = z.string().min(3).max(20);
const emailSchema = z.string().email();
```
### Number
Defining numbers is equally straightforward:

```typescript
const numberSchema = z.number().int().positive();
```
This ensures that the value is an integer and positive.

### Booleans
Booleans are, unsurprisingly, even simpler:

```typescript
const booleanSchema = z.boolean();
```
### Arrays
The library makes working with arrays a breeze:

```typescript
const stringArraySchema = z.array(z.string());
```
This creates a schema for an array of strings.

### Objects
Creating complex nested objects is where the library really shines. Here's how you can define an object schema:

```typescript
const userSchema = z.object({
  username: z.string().min(3),
  age: z.number().positive(),
  email: z.string().email(),
});
```
With this schema, you can easily validate user data.

### Unions

You can also define unions of different types:

```typescript
const stringOrNumberSchema = z.union([z.string(), z.number()]);
```
This schema allows values that are either strings or numbers.

### Intersections

Intersections allow you to combine multiple schemas:

```typescript
const userSchema = z.object({
  username: z.string().min(3),
  age: z.number().positive(),
});

const emailSchema = z.object({
  email: z.string().email(),
});

const userWithEmailSchema = z.intersection([userSchema, emailSchema]);
```
This schema ensures that the data matches both the user and email schemas.

This is just a taste of what you can do with the library's primitive types. You can combine them in various ways to create complex schemas that match the structure of your data.

## Guides and Concepts
So, how do you use these schemas in real-world applications? Let's look at some practical guides and concepts.

### Schema Validation
Once you've defined a schema, you can use it to validate data. The library provides a `parse` method that you can use to validate and parse data:

```typescript
function createUser(user: unknown) {
  userSchema.parse(user);
  // If the function gets here, the validation is successful
}
```
If the data doesn't match the schema, the library will throw an error with detailed information about what went wrong.

### Optional and Nullable
You can define `optional` and `nullable` fields in your schemas:

```typescript
const userSchema = z.object({
  username: z.string().min(3),
  age: z.number().positive().optional(),
  email: z.string().email().nullable(),
});
```
The `optional` method allows the field to be omitted, while the `nullable` method allows the field to be `null`.

### Handling Errors
The library's error handling is comprehensive and developer-friendly. You can either catch the error thrown by parse or use safeParse to handle it more gracefully:

```typescript
const result = userSchema.safeParse(userInput);

if (!result.success) {
  console.error(result.error.errors);
}
```
This way, you can log the errors and provide feedback to the user. The error messages are detailed and informative, making it easy to pinpoint the issue.

### Transformations
The library allows you to transform data as part of the validation process. You can use the `transform` method to apply a function to the data before validating it:

```typescript
const numberStringSchema = z.string().transform(val => parseFloat(val));

const val = numberStringSchema.parse("123.45"); // val will be 123.45 as number
```
This can be useful for normalizing data or converting it to a different format.

## Why Use This Library?
The library isn't the only schema validation tool out there. How does it stack up against others like Joi or Yup?

### TypeScript-First
One of the most compelling features is its TypeScript-first approach. While other libraries like Yup and Joi have TypeScript support as an afterthought, this one is built with TypeScript in mind, ensuring type safety and coherence.

### Ease of Use
When compared to Joi, this library's API is much more intuitive. No more second-guessing method names or parameters; it is straightforward and developer-friendly.

### Bundle Size
For frontend developers concerned about bundle size, it has the edge over Joi. The library is lightweight and easy to tree-shake.

### Validation and Transformation
Yup is known for its powerful validation and transformation capabilities, but this library is catching up fast. With its chainable API and intuitive methods, it is becoming the go-to option for many developers.

## Conclusion
This library is a powerful and versatile tool that makes data validation a breeze. By combining it with TypeScript, you can ensure that your frontend applications are robust, type-safe, and performant. Whether you're validating form data, API responses, or state updates, this tool has you covered. Be it simple primitives or complex nested objects, it can handle it all.

In this article, we've only scratched the surface of what this library can do. I encourage you to explore the documentation and experiment with different schemas to see how it can help you build better frontend applications. Embrace the power of type-safe data validation and let this library simplify your development workflow.

Happy coding!

Last updated on August 17, 2024
