Published on

How to Omit Fields from Nested Zod Schemas

Authors
  • Name
    Ripal & Zalak
    Twitter

How to Remove Fields from Nested Zod Schemas

Sometimes, while working with Zod schemas in TypeScript, you might need to remove certain fields from a nested schema. Instead of just making them optional, you might want to completely exclude them. Thankfully, Zod provides simple ways to achieve this.


Problem

Imagine you have a schema like this:

import { z } from 'zod'

const schema = z.object({
  name: z.number(),
  age: z.number(),
  data: z.array(
    z.object({
      id: z.string().optional(),
      name: z.string().nonempty().optional(),
    })
  ),
})

Here, the data field is an array of objects, each containing id and name. Now, let’s say you want to remove the name field from this nested schema.


Solution

1. Using omit

You can use Zod's omit method to exclude specific fields from a schema. Here’s how:

const updatedSchema = schema.shape.data.element.omit({ name: true }).array()

// Type inference
type UpdatedType = z.infer<typeof updatedSchema>

In this example:

  • schema.shape.data.element accesses the schema for the individual items inside the data array.
  • .omit({ name: true }) removes the name field from that schema.
  • .array() ensures the updated schema remains an array.

2. Modular Schema Design

A better way to handle schema variations is by breaking them into smaller, reusable parts. For example:

import { z } from 'zod'

// Base schema for data
const baseDataSchema = z.object({
  id: z.string().optional(),
  value: z.number(),
})

// Extended schema with additional fields
const extendedDataSchema = baseDataSchema.merge(
  z.object({
    name: z.string().optional(),
  })
)

// Schema without 'name'
const noNameSchema = baseDataSchema

// Type inference
type BaseData = z.infer<typeof noNameSchema>
type ExtendedData = z.infer<typeof extendedDataSchema>

This approach allows you to create and manage different versions of the schema effortlessly.


Why Use omit?

  1. Clean and Precise: The omit method directly removes fields from a schema without making them optional.
  2. Flexibility: Perfect for scenarios where certain fields shouldn’t exist at all.
  3. Type Safety: Updated schemas automatically infer the correct TypeScript types.

Complete Example

Here’s a complete example combining both approaches:

import { z } from 'zod'

// Original schema
const schema = z.object({
  name: z.number(),
  age: z.number(),
  data: z.array(
    z.object({
      id: z.string().optional(),
      name: z.string().nonempty().optional(),
    })
  ),
})

// Remove 'name' from the nested schema
const updatedSchema = schema.shape.data.element.omit({ name: true }).array()

// Modular schema design
const baseDataSchema = z.object({
  id: z.string().optional(),
  value: z.number(),
})

const extendedDataSchema = baseDataSchema.merge(z.object({ name: z.string().optional() }))

const noNameSchema = baseDataSchema

// Type inference
type DataWithoutName = z.infer<typeof updatedSchema>

FAQs

Q: Why not just make the field optional? Making a field optional (optional()) means it can still exist in the schema, but its value can be undefined. Using omit() ensures the field is entirely removed.

Q: Can I use this for deeply nested schemas? Yes! You can chain omit() with other Zod methods to handle complex nested structures.

Q: What if I need to add fields later? Use merge() to extend schemas with additional fields as required.