2.4 KiB
UnionSchema
(no submodules)
Purpose
UnionSchema validates that an input satisfies at least one of a list of member schemas. It short-circuits on the first successful parse, returning that result without checking remaining members. When all members fail, it aggregates all their issues into the ValidationError, giving the caller visibility into why each arm failed.
Features
- Short-circuit success: first matching schema wins
- All-failure aggregation: every arm's issues collected into one
ValidationError - Empty union: always fails with
VALIDATION.UNION.NO_MATCH
Usage: Basic Example
import { union, string, number } from "@suaveplan/validation";
const stringOrNumber = union([string(), number()]);
stringOrNumber.parse("hello"); // "hello"
stringOrNumber.parse(42); // 42
stringOrNumber.parse(true); // throws ValidationError
Usage: Advanced Example
import { union, literal, object, string } from "@suaveplan/validation";
// Discriminated union
const Event = union([
object({ type: literal("created"), id: string() }),
object({ type: literal("deleted"), id: string(), reason: string() }),
]);
Event.parse({ type: "created", id: "abc" });
// { type: "created", id: "abc" }
API Reference
union(schemas: AnySchema[]): UnionSchema
Factory accepting an array of member schemas.
_parse(input, ctx): unknown | INVALID
Iterates schemas in order. Returns the first non-INVALID result. On all-failure, pushes all collected issues to ctx.issues and returns INVALID. Empty union always adds a single VALIDATION.UNION.NO_MATCH issue.
Implementation Notes
- Each arm runs with its own
childCtxso its issues don't contaminate the parent context until the all-failure path is confirmed. - The order of schemas matters: place more specific schemas first to avoid false positives from permissive schemas like
string(). - The aggregated issue list can be long for wide unions; callers may want to use
flatten()to extract meaningful field-level errors.
Parse Behaviour
z.union([a, b, c]) tries each member in order and returns the first success; all failures are aggregated into a ZodUnionError with per-member diagnostics so callers can show a useful error. For discriminated unions (a shared literal key across members), prefer z.discriminatedUnion("kind", [...]) which is faster and produces cleaner errors.