Using Zod with TypeScript: A Guide for Frontend Developers
Harshal Ranjhani

Harshal Ranjhani @harshalranjhani

About: Full Stack Developer and Technical Writer!

Location:
Pune, India
Joined:
Sep 26, 2023

Using Zod with TypeScript: A Guide for Frontend Developers

Publish Date: Aug 17 '24
117 19

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.

// tsconfig.json
{
  // ...
  "compilerOptions": {
    // ...
    "strict": true
  }
}
Enter fullscreen mode Exit fullscreen mode

To get started, install the library using npm or yarn:

npm install zod
Enter fullscreen mode Exit fullscreen mode

Or if you're using yarn:

yarn add zod
Enter fullscreen mode Exit fullscreen mode

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:

import { z } from "zod";

const stringSchema = z.string();
Enter fullscreen mode Exit fullscreen mode

You can also enforce various constraints like minimum and maximum lengths, or specific patterns:

const usernameSchema = z.string().min(3).max(20);
const emailSchema = z.string().email();
Enter fullscreen mode Exit fullscreen mode

Number

Defining numbers is equally straightforward:

const numberSchema = z.number().int().positive();
Enter fullscreen mode Exit fullscreen mode

This ensures that the value is an integer and positive.

Booleans

Booleans are, unsurprisingly, even simpler:

const booleanSchema = z.boolean();
Enter fullscreen mode Exit fullscreen mode

Arrays

The library makes working with arrays a breeze:

const stringArraySchema = z.array(z.string());
Enter fullscreen mode Exit fullscreen mode

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:

const userSchema = z.object({
  username: z.string().min(3),
  age: z.number().positive(),
  email: z.string().email(),
});
Enter fullscreen mode Exit fullscreen mode

With this schema, you can easily validate user data.

Unions

You can also define unions of different types:

const stringOrNumberSchema = z.union([z.string(), z.number()]);
Enter fullscreen mode Exit fullscreen mode

This schema allows values that are either strings or numbers.

Intersections

Intersections allow you to combine multiple schemas:

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]);
Enter fullscreen mode Exit fullscreen mode

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:

function createUser(user: unknown) {
  userSchema.parse(user);
  // If the function gets here, the validation is successful
}
Enter fullscreen mode Exit fullscreen mode

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:

const userSchema = z.object({
  username: z.string().min(3),
  age: z.number().positive().optional(),
  email: z.string().email().nullable(),
});
Enter fullscreen mode Exit fullscreen mode

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:

const result = userSchema.safeParse(userInput);

if (!result.success) {
  console.error(result.error.errors);
}
Enter fullscreen mode Exit fullscreen mode

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:

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

const val = numberStringSchema.parse("123.45"); // val will be 123.45 as number
Enter fullscreen mode Exit fullscreen mode

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!

Comments 19 total

  • Anmol Baranwal
    Anmol BaranwalAug 17, 2024

    I first noticed it when I was using shadcn. Zod + react form hooks make a deadly combo :)

  • Mostafa
    MostafaAug 17, 2024

    Library you will not see it in any real big projects in big companies, maybe startup will focus in such things. Master typescript and build your own schemes and model your data and that's fine and for form validation or any input fields create a well defined validation use regex and that's perfect, remember to keep it simple and extendable.
    Just FYI, Zod was a stupid solution to build a bridge between types front end and back end, it's used in another stupid solution tRPC, after couple of years you will not hear a lot or even at all about them.

    • Vu Tung Lam
      Vu Tung LamAug 18, 2024

      I think a library is born to solve certain problems, not none. In this case, Zod is to validate the data. If you simply use TS types and silly checks such as if typeof x === "string" then you are really missing out nice libraries like Zod that could make life much easier.

      Also, just because big companies do not use it, doesn't mean it is bad. Some big companies are even notorious for their ancient, convoluted and not-so-maintainable codebase.

      • Mostafa
        MostafaAug 18, 2024

        Zod and smilliar libraries just a handy tool for non knowledgeable developers which like to run the stuff in localhost environment, 2 years ago I was refactoring in a project for Samsung I uninstalled almost 5 useless libraries from the system, one of them was Zod!
        I tell you something, when the front end developer doesn't know a lot about design systems for sure he will fall in love with such Zod because he want his code just work when you build app for coffee shop or hairdresser, but if you're building a product for 1 billions users and your app has a massive services behind the scenes, you will start to draw and design, not installing Zod. Now I think if you're not that person then you're missing a huge opportunity to become a real developer in a real projects with a big clients 😉

        • Vu Tung Lam
          Vu Tung LamAug 18, 2024

          I certainly can design backend systems and at the same time install Zod at the frontend. They are not mutually exclusive. Using Zod is not an indication of stupidity. Big systems are not prohibited from using Zod, either.

          I believe you saw a very bad use of Zod in that codebase, and you refactored it, that's nice - but, just because Zod is used in smelling code, doesn't mean Zod itself is bad.

          I personally believe that schema validation libraries like Zod, TypeBox, etc. help a lot when you are building large systems that interact with lots of external services, especially when you are using a duck-typed language such as JS/TS (you know TS is not very strong typed with that any type). I once had to use TypeBox to validate the responses returned by PayPal API endpoints - you know how poor their docs are - and that just revealed a whole lot of silly errors the previous developers overlooked and then I had to fix.

          So we see, some libraries are born to solve some problems. Usually libraries like Zod are quite heavily tested, so instead of doing silly type checks and regexes all over the place in your code which is error-prone and adding burden of testing, you can use a library, and some level of reliability is already guaranteed. It saves a lot of time and effort.

          Having said that, poor use of any libraries or techniques should be addressed, whether it is a "localhost" project, a startup project, or a giant business' one.

          • Mostafa
            MostafaAug 18, 2024

            I agree with you, Zod is solving some problem, but my point is when you're working in a big projects for big clients you will be building/ creating a library to solve the same problem! You may ask me but why not installing Zod and save the time instead? It's well tested and I can see from npm weekly downloads over millions!! Well I can answer you, first of all when you're using external library the versioning is out of your control if your business requirements faster than the release path of Zod , then you need to open a bug for Zod GitHub community and 🙏 pray to they create a pull request fast and solve the issue ! Well that's fine you can inform your client we have to wait 🙂 there is a software limitation over there, but again who is your client ? BMW, Mercedes, Toyota, or maybe Lamborghini or even NASA? Or your client is X which is selling flipflops by $10? 2nd category of clients will be ok very ok but first group of clients will not even allow for such things to happen, that's why they invest money and hire real developers so they can ask them to create libraries and contribute in their ecosystem.
            That's why you can see in an interview a question about react hook, but in other interview for other clients a question about design system and DSA. I hope you got my point.

            • Kevin Berry
              Kevin BerryAug 18, 2024

              @freelancer2020 can you expand more on what you mean by this?

              “when you're working in a big projects for big clients you will be building/ creating a library to solve the same problem“

              For big clients you roll your own schema validation?

              Or you build something else that covers what zod is solving?

    • ImTheDeveloper
      ImTheDeveloperAug 18, 2024

      Poor comment.

      • Mostafa
        MostafaAug 18, 2024

        I smell startup right here

    • Konstantin Bläsi
      Konstantin BläsiAug 18, 2024

      So you just don't parse, validate and filter or just write everything from scratch, basically creating yet another framework. You're also writing your own http clients because you can? Are you not developing your own hardware yet at

      • Mostafa
        MostafaAug 20, 2024

        Hardware always on the table when we're developing a software, when I am writing application that will fork a process or run some stuff in different threads, I do test with different hardware as well. CPUs, Ram's and even SSD for swapping from ram to SSD and vice versa, when I am writing online game of course I need to know how many core the customer owns, so I can load the settings properly
        It's not about that you will be writing a files that will be executed in the browser program so you don't care about hardware!
        At the end it's bits! You need to understand the hardware, did you ask yourself one day why window object in JavaScript has a screen object which provide you with some information about the screen as a piece of hardware? There is even color depth beside width, height and screen orientation etc.. open web API's many of them now doing some operations with hardware, for example 🔋 battery manager interface🔋
        Now I can answer your question
        I am not developing a hardware, but I do understand it.

  • Jonathan Gamble
    Jonathan GambleAug 18, 2024

    Zod is not tree shakable, so too big and slow, use Valibot.

    • Martin Baun
      Martin BaunAug 19, 2024

      Zod has one of the best APIs and ecosystems, but fairly slow types and parsing compared to its competition. But also it’s good enough so if you like it just use it, why not :)

    • Sheraz Manzoor
      Sheraz ManzoorAug 19, 2024

      I stand with you mate.
      It is okay to use zod for small projects but for large scale project valibot is best choice

  • George WL
    George WLAug 18, 2024

    Why does the image look weird and ugly? Did you make it blindfolded?

  • João Angelo
    João AngeloAug 19, 2024

    Hi Harshal Ranjhani,
    Top, very nice and helpful !
    Thanks for sharing.

  • mohamed karim
    mohamed karimAug 19, 2024

    Thank for sharing

  • Evgeny Karpel
    Evgeny KarpelAug 20, 2024

    And how to treat tuples here?

  • MexiKode ⚙
    MexiKode ⚙Aug 20, 2024

    complexity for the sake of being clever.
    roll your own dont be lazy

Add comment