Distributed Zod discriminated unions
Here’s a trick that seems obvious in retrospect. If you want to represent a type like this in Zod:
type Order = { name: string } & (
| { orderType: 'DELIVERY'; details: DeliveryOrderDetails }
| { orderType: 'PICKUP'; details: PickupOrderDetails }
);TypeScript
You can just create the union type separately and then intersect it:
const OrderDetails = z.discriminatedUnion('orderType', [
z.object({
orderType: z.literal('DELIVERY'),
details: DeliveryDetailsSchema,
}),
z.object({
orderType: z.literal('PICKUP'),
details: PickupDetailsSchema,
}),
]);
const OrderSchema = z.object({ name: z.string() }).and(OrderDetails);
// Or this:
// const OrderSchema = z.intersection(z.object({ name: z.string() }), OrderDetails);TypeScript
Neat if you’re forced to keep the type discriminator top-level.