logo
eng-flag

Zod Cheatsheet

Table of Contents

  1. Installation
  2. Basic Usage
  3. String Schemas
  4. Number Schemas
  5. Boolean Schemas
  6. Date Schemas
  7. Array Schemas
  8. Object Schemas
  9. Union and Intersection Types
  10. Enum Schemas
  11. Optional and Nullable
  12. Custom Validation
  13. Error Handling
  14. Parsing and Safeparsing
  15. Integration with React

Installation

Install Zod:

npm install zod

Basic Usage

Basic schema definition and validation:

import { z } from 'zod';

const schema = z.object({
  name: z.string(),
  age: z.number().positive().int(),
  email: z.string().email(),
});

type User = z.infer<typeof schema>; // Infer TypeScript type from schema

const result = schema.safeParse({
  name: 'John Doe',
  age: 30,
  email: 'john@example.com',
});

if (result.success) {
  console.log('Valid data:', result.data);
} else {
  console.log('Validation errors:', result.error.errors);
}

String Schemas

Various string validation methods:

const stringSchema = z.object({
  username: z.string()
    .min(3, 'Username must be at least 3 characters')
    .max(20, 'Username must not exceed 20 characters')
    .regex(/^[a-zA-Z0-9]+$/, 'Username can only contain alphanumeric characters'),
  email: z.string().email('Invalid email address'),
  password: z.string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
    .regex(/[0-9]/, 'Password must contain at least one number'),
  url: z.string().url('Invalid URL'),
});

Number Schemas

Number validation methods:

const numberSchema = z.object({
  age: z.number()
    .positive('Age must be a positive number')
    .int('Age must be an integer')
    .min(18, 'Must be at least 18 years old')
    .max(100, 'Must be at most 100 years old'),
  price: z.number()
    .positive('Price must be positive')
    .multipleOf(0.01, 'Price must have at most 2 decimal places')
    .max(1000000, 'Price must be less than 1,000,000'),
});

Boolean Schemas

Boolean validation:

const booleanSchema = z.object({
  agreeToTerms: z.boolean()
    .refine((val) => val === true, 'You must agree to the terms'),
  receiveNewsletter: z.boolean().optional(),
});

Date Schemas

Date validation methods:

const dateSchema = z.object({
  birthDate: z.date()
    .max(new Date(), 'Birth date cannot be in the future'),
  appointmentDate: z.date()
    .min(new Date(), 'Appointment date must be in the future'),
});

Array Schemas

Array validation methods:

const arraySchema = z.object({
  tags: z.array(z.string())
    .nonempty('At least one tag is required')
    .max(5, 'Maximum 5 tags allowed'),
  scores: z.array(z.number().positive().int())
    .min(3, 'At least 3 scores are required'),
});

Object Schemas

Nested object validation:

const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
  zipCode: z.string().regex(/^d{5}$/, 'Invalid zip code'),
});

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  address: addressSchema,
});

Union and Intersection Types

Using union and intersection types:

const unionSchema = z.union([
  z.string(),
  z.number(),
  z.boolean(),
]);

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

Enum Schemas

Creating enum schemas:

const RoleEnum = z.enum(['admin', 'user', 'guest']);

const userSchema = z.object({
  name: z.string(),
  role: RoleEnum,
});

Optional and Nullable

Handling optional and nullable fields:

const schema = z.object({
  name: z.string(),
  middleName: z.string().optional(),
  nickname: z.string().nullable(),
  age: z.number().optional().nullable(),
});

optional(): The field may or may not be present (its value can be undefined if not provided).
nullable(): The field must be present but can be explicitly set to null.

Custom Validation

Creating custom validation rules:

const customSchema = z.object({
  password: z.string()
    .min(8)
    .refine((val) => /[A-Z]/.test(val), 'Password must contain an uppercase letter')
    .refine((val) => /[0-9]/.test(val), 'Password must contain a number'),
  confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
  message: "Passwords don't match",
  path: ["confirmPassword"],
});

Error Handling

Handling validation errors:

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

const result = schema.safeParse({ name: '', email: 'invalid' });

if (!result.success) {
  console.log('Validation errors:');
  result.error.issues.forEach((issue) => {
    console.log(`${issue.path.join('.')}: ${issue.message}`);
  });
}

Parsing and Safeparsing

Using parse and safeparse methods:

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

// Parsing (throws error if invalid)
try {
  const data = schema.parse({ name: 'John', age: '30' });
  console.log('Parsed data:', data);
} catch (error) {
  if (error instanceof z.ZodError) {
    console.log('Validation errors:', error.errors);
  }
}

// Safeparsing (returns success/error object)
const result = schema.safeParse({ name: 'John', age: '30' });
if (result.success) {
  console.log('Valid data:', result.data);
} else {
  console.log('Validation errors:', result.error.errors);
}

Integration with React

Using Zod with React and a form library like React Hook Form:

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

const schema = z.object({
  name: z.string().min(1, 'Name is required'),
  email: z.string().email('Invalid email'),
});

type FormData = z.infer<typeof schema>;

function Form() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  const onSubmit = (data: FormData) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name")} />
      {errors.name && <p>{errors.name.message}</p>}
      
      <input {...register("email")} />
      {errors.email && <p>{errors.email.message}</p>}
      
      <button type="submit">Submit</button>
    </form>
  );
}

2024 © All rights reserved - buraxta.com