Telerik blogs

Discover how Zod can help improve your code’s type safety, leading to better software and a smoother development experience. Plus it easily integrates with existing TypeScript and JavaScript projects.

In programming, type safety is crucial for preventing runtime errors and better supporting your code’s robustness. One way to achieve this in JavaScript and TypeScript is by utilizing Zod, a powerful library designed for schema validation and parsing. This article will introduce you to the benefits of making your code type-safe and how you can implement Zod to enhance the quality and reliability of your projects.

Zod offers a straightforward, declarative syntax that lets you set strict data validation rules for various data types. By adopting Zod in your development process, you can catch potential type-related issues early on, reducing debugging time and promoting a more maintainable codebase.

Getting started with Zod is simple, as it seamlessly integrates with existing TypeScript and JavaScript projects. As you explore the various features and possibilities that Zod provides, you’ll discover how it can help improve your code’s type safety, ultimately leading to better software and a smoother development experience.

Understanding Type Safety

Type safety is an essential aspect of programming that helps you minimize errors and enhance the maintainability of your code. Ensuring that you use the correct data types in your application can catch potential problems early in the development process. This is where Zod comes into play. This library allows you to create type-safe code efficiently.

When working with type-safe code, you benefit from the knowledge that the data types you expect are the ones you are receiving. This reduces the need for excessive data validation and promotes a clean, streamlined architecture. Zod makes this even more accessible by providing expressive and powerful schemas that can easily be incorporated into your projects.

As a practical example, imagine you are working with user-submitted data. With Zod, you can define a schema that maps all the different fields from the data to their respective types and requirements. Once you’ve created the schema, Zod ensures all user data adheres to the defined rules, helping you catch bugs and potential issues before they become critical.

Using Zod and focusing on type safety makes your code more understandable, reliable and easier to maintain. You will also appreciate the improved debugging experience and the confidence gained by knowing your code is less prone to unexpected errors. So, with Zod at your side, you are on your way to creating safer and more reliable code.

Getting Started with Zod

To get started, you need to install Zod into your project by running one of the commands:

npm install zod
yarn add zod

Once installed, you can start creating schemas to define the data structure and types you expect, like this:

import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
  age: z.number().min(0),
  country: z.string().optional(),
});

In this schema, you define a person object with three properties: name (a required string), age (a required positive number) and country (an optional string). You can use Zod’s built-in functions like min() and optional() to set constraints on the data.

Validating data using the defined schema is straightforward. You can use your schema’s parse() method to validate and parse the data. The data will be returned as a typed object if it passes validation. Otherwise, an error will be thrown:

try {
  const validUser = userSchema.parse({
    name: 'John Doe',
    age: 30,
  });
  console.log(validUser); // { name: 'John Doe', age: 30 }
} catch (error) {
  console.log(error.message);
}

Type Inference

Additionally, Zod works well with TypeScript, as you can leverage Zod’s infer utility to create a type based on your schema. This enables strong typing and autocompletion in your editor:

import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
  age: z.number().min(0),
  country: z.string().optional(),
});

type User = z.infer<typeof userSchema>;

With this schema defined, you can validate your user objects using the Zod’s parse method, for example:

// User object with correct data types
const validUser: User = {
  name: "John",
  age: 26,
  country: "Brazil",
};

// This will pass without errors
UserSchema.parse(validUser);

// User object with incorrect data types
const invalidUser: User = {
  name: "Jane",
  age: "30", // age should be a number
  country: "Brazil",
};

// This will throw a ZodError
UserSchema.parse(invalidUser);

Custom Validation

Zod provides custom validation via refinements. It was designed to mirror TypeScript as closely as possible. But there are many so-called “refinement types” you may wish to check for that can’t be represented in TypeScript’s type system. For instance, you check whether a number is an integer or a string is a valid email address.

const myString = z.string().refine((val) => val.length <= 255, {
  message: "String can't be more than 255 characters",
});

Zod also allows you to create custom validation rules using the refine method. This is useful when your data needs to meet specific conditions beyond the data type. For example, you can add a rule that requires the user’s age to be at least 18:

const UserSchema = z.object({
  name: z.string(),
  age: z.number().refine((value) => value >= 18, {
    message: "Age must be at least 18",
  }),
  email: z.string().email(),
});

Complex Schema Objects

Sometimes, we want to compose many objects into a single one. We can do that with Zod, too. We can prevent duplication of code and the creation of complex code.

import * as z from "zod";

const professionSchema = z.object({
  name: z.string(),
  company: z.string(),
  address: z.string(),
  since: z.string()
});

const userSchema = z.object({
  name: z.string(),
  age: z.number().refine((value) => value >= 18, {
    message: "Age must be at least 18"
  }),
  email: z.string().email(),
  profession: professionSchema
});

type User = z.infer<typeof userSchema>;

const newUser: User = {
  name: "John Doe",
  age: 30,
  email: "john@doe.com",
  profession: {
    name: "Software Engineer",
    company: "Telerik",
    address: "Street 101",
    since: "2021"
  }
};

console.log(newUser);

Conclusion

Adopting Zod into your coding practices offers numerous benefits for type-safety and reducing runtime errors. By leveraging Zod to validate and parse data, you can improve the integrity and consistency of your code, simplifying maintenance and enhancing efficiency.

To maximize the advantages of Zod, take the time to explore its rich feature set, including the support for custom validators, refinement and versatile error handling. The more you apply these tools, the more confident and secure your code will become.

Finally, remember that adopting best practices like using Zod for type safety enhances your code quality and contributes to the overall growth of your coding skills. Keep refining your techniques to stay ahead in the world of modern programming.


Leonardo Maldonado
About the Author

Leonardo Maldonado

Leonardo is a full-stack developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.

Related Posts

Comments

Comments are disabled in preview mode.