UnionSchema
Accepts a value that matches any one of several schemas. Options are tried in order and the first that succeeds decides the result, so when two options overlap the earlier one wins — put the narrower option first if you want it to be the one that parses.
local Id = v.union({ v.string():min(1), v.number():integer() })
Id:parse("player_1") --> "player_1"
Id:parse(7) --> 7
Id:parse(true) --> errors
A tagged shape falls out of combining LiteralSchema with ObjectSchema,
which is how a union of message kinds is usually written. Annotate each tag
as a singleton, since Vet.literal otherwise widens it to string and the
arms become indistinguishable to Luau:
local Join: v.LiteralSchema<"join"> = v.literal("join")
local Chat: v.LiteralSchema<"chat"> = v.literal("chat")
local Event = v.union({
v.object({ kind = Join, userId = v.number() }),
v.object({ kind = Chat, text = v.string() }),
})
local event = Event:parse(payload)
if event.kind == "chat" then
print(event.text) -- narrowed to the chat arm
end
Nothing matching is a failure of the union as a whole rather than of any one option, so the issue sits at the union's own path and its message names each option and why that option rejected the value.
Properties
options
This item is read only and cannot be modified. Read OnlyReflectionUnionSchema.options: {AnySchema<any>}The schemas this union was built from, in the order they are tried:
local Id = v.union({ v.string(), v.number() })
#Id.options --> 2
Id.options[1]:parse("") --> ""
The table is a frozen copy of the one passed to Vet.union, so mutating it fails loudly rather than corrupting the schema.
isOptional
This item is read only and cannot be modified. Read OnlyReflectionUnionSchema.isOptional: boolean
true when any option accepts nil, since then the union does too.
A DefaultSchema option does not count: it accepts a missing value but
fills one in, so the union still never produces nil.
access
This item is read only and cannot be modified. Read OnlyReflectionUnionSchema.access: "readwrite"
Always "readwrite", whatever the options carry. An option's marker
says how that option would sit in an object, not how the union does.
Functions
safeParse
ParsingUnionSchema:safeParse(value: unknown) → Result<T>Tries each option in order and returns what the first match parsed to. When none match, the single issue reports every option's rejection.
parse
ParsingUnionSchema:parse(value: unknown) → TValidates value and returns it, throwing on failure.
Errors
| Type | Description |
|---|---|
| "expected one of ..." | Thrown when no option accepts `value` |
optional
WrapperWraps this schema so that nil is also accepted.
default
Wrapper
Wraps this schema so that nil yields fallback instead of failing.
Prefer passing a function when the fallback is a table, since a constant
one would be shared by every parse.
defaultWith
WrapperUnionSchema:defaultWith(produce: () → T--
Builds the value used when parsing nil
) → DefaultSchema<T>
Like :default, but calls produce on every parse instead of reusing
one value.
The produced value is validated each time.
readonly
WrapperWraps this schema so that a field using it is typed read.
writeonly
WrapperWraps this schema so that a field using it is typed write.