- Published on
How to Merge Multiple Zod Object Schemas: A Complete Guide
- Authors
- Name
- Ripal & Zalak
How to Merge Multiple Zod Object Schemas: A Complete Guide
Merging multiple Zod object schemas can be essential for building complex validation rules in your TypeScript applications. Whether you’re working with form validations, APIs, or custom logic, Zod provides powerful utilities for combining schemas effectively.
In this guide, we’ll explore several methods to merge Zod schemas, focusing on practical examples and best practices.
The Problem
You have three schemas for different types of blog posts:
- Image Post: Requires an image attachment and optional text.
- Video Post: Requires a video attachment and optional text.
- Text Post: Requires text only, with no attachments.
Here are the schemas:
import { z } from 'zod'
const imagePostSchema = z.object({
body: z.string().max(500).optional().or(z.literal('')),
attachmentType: z.literal('img'),
attachment: z.string().url(), // Assume URL for simplicity
})
const videoPostSchema = z.object({
body: z.string().max(500).optional().or(z.literal('')),
attachmentType: z.literal('video'),
attachment: z.string().url(), // Assume URL for simplicity
})
const textPostSchema = z.object({
body: z.string().max(500),
attachmentType: z.null(),
attachment: z.null(),
})
Now, the goal is to merge these schemas into a single schema to allow users to submit any type of post.
Solution 1: Use z.union for Unions
The simplest way to merge schemas is by creating a union using z.union. This approach validates objects that match any one of the provided schemas.
Implementation:
const postSchema = z.union([imagePostSchema, videoPostSchema, textPostSchema])
Usage:
const result = postSchema.safeParse({
body: 'Check out this image!',
attachmentType: 'img',
attachment: 'https://example.com/image.jpg',
})
console.log(result.success) // true if valid
Solution 2: Use z.discriminatedUnion for Discriminated Unions
If the schemas can be distinguished by a common field, such as attachmentType, you can use z.discriminatedUnion for better performance and type inference.
Implementation:
const postSchema = z.discriminatedUnion('attachmentType', [
imagePostSchema,
videoPostSchema,
textPostSchema,
])
Why Use z.discriminatedUnion?
- Performance: It only checks the schema corresponding to the
attachmentTypevalue. - Type Inference: TypeScript infers the correct type based on the discriminant.
Usage:
const result = postSchema.safeParse({
body: 'Watch this video!',
attachmentType: 'video',
attachment: 'https://example.com/video.mp4',
})
if (result.success) {
console.log(result.data.attachmentType) // "video"
}
Solution 3: Combine Schemas with z.object Spreading
If you want to merge all schemas into a single comprehensive schema, you can use the shape property to spread their fields.
Implementation:
const combinedSchema = z.object({
...imagePostSchema.shape,
...videoPostSchema.shape,
...textPostSchema.shape,
})
Use Case:
This approach is useful when the fields from all schemas need to coexist in one schema.
Drawback:
This doesn’t enforce mutual exclusivity between schema types. Use unions or discriminated unions for stricter validation.
Solution 4: Use z.intersection for Common Validations
If you need to combine schemas with overlapping validations, use z.intersection.
Implementation:
const sharedSchema = z.intersection(imagePostSchema, videoPostSchema)
Drawback:
This method works for AND logic (objects must satisfy both schemas) and is not suitable for mutually exclusive schemas like in this use case.
Best Practices
- Prefer
z.discriminatedUnion: When a common field distinguishes schemas, it’s the most efficient and type-safe method. - Avoid
z.intersectionfor Unions: Use it only for overlapping fields withANDlogic. - Validate Early: Use
safeParseorparseat data entry points to catch errors early. - Leverage TypeScript: Type inference from Zod improves code reliability and developer experience.
Conclusion
Merging multiple Zod schemas depends on your specific requirements:
- Use
z.unionfor basic combinations. - Use
z.discriminatedUnionfor efficient validation with a shared field. - Use schema spreading for comprehensive schema creation.
By following these approaches, you can build robust and flexible validation logic for your applications.
Key Takeaways
z.union: Simple merging of schemas.z.discriminatedUnion: Efficient validation with type inference.- Schema Spreading: Combine fields into one schema.
z.intersection: Combine schemas with overlapping validations.
With these techniques, you can manage complex validation scenarios effectively using Zod in TypeScript.
