Union and variant examples
Problem
Model polymorphic payloads, IDs that can arrive in multiple formats, and discriminated events without losing runtime validation or output typing.
Runnable Example
ts
import { v } from '@vielzeug/validit';
const IdSchema = v.union(v.coerce.number().int().positive(), v.string().uuid());
IdSchema.parse('42');
// => 42 (number) because the first branch succeeds
const RoleSchema = v.union('admin', 'editor', 'viewer');
RoleSchema.parse('admin');
const WithId = v.object({ id: v.number().int().positive() });
const WithAudit = v.object({ createdAt: v.date() });
const EntitySchema = v.intersect(WithId, WithAudit);
const EventSchema = v.variant('type', {
user_created: v.object({ userId: v.number().int().positive() }),
user_deleted: v.object({ userId: v.number().int().positive(), reason: v.string() }),
});
EventSchema.parse({ type: 'user_created', userId: 10 });
EventSchema.parse({ type: 'user_deleted', userId: 10, reason: 'requested' });
const ActionSchema = v.variant('type', {
create: v.object({ name: v.string() }),
remove: v.object({ id: v.number().int().positive() }),
});
ActionSchema.safeParse({ type: 'create', name: 'A', extra: true }); // fails (strict object mode)
enum Status {
Draft = 'draft',
Published = 'published',
}
const StatusSchema = v.nativeEnum(Status);
StatusSchema.parse(Status.Draft);Expected Output
union()returns the first successful branch result.intersect()requires every branch to pass and merges object outputs from successful branches.variant()chooses one object branch by discriminator instead of trying every branch.
Common Pitfalls
- Ordering permissive union branches before strict branches.
- Assuming intersection merges incompatible values automatically.
- Using
variantmaps where branch values are not object schemas.