A decoder that tries each decoder in sequence until one succeeds
const stringOrNumber = JsonDecoder.oneOf<string | number>([
JsonDecoder.string(),
JsonDecoder.number()
]);
stringOrNumber.decode('hello'); // Ok<string>
stringOrNumber.decode(42); // Ok<number>
stringOrNumber.decode(true);
// Err({ issues: [
// { message: 'no alternative matched (tried 2)', path: [] },
// { message: 'true is not a valid string or true is not a valid number', path: [] }
// ] })
// Every alternative's failure is reported. For `X | null`, prefer nullable(X)
// which delegates to X and yields just X's error.
const circle = JsonDecoder.object({
kind: JsonDecoder.literal('circle'),
radius: JsonDecoder.number()
});
JsonDecoder.oneOf([circle, JsonDecoder.null()]).decode({ kind: 'circle', radius: 'big' });
// Err({ issues: [
// { message: 'no alternative matched (tried 2)', path: [] },
// { message: '{"kind":"circle","radius":"big"} is not null', path: [] },
// { message: '"big" is not a valid number', path: ['radius'] }
// ] })
JsonDecoder.nullable(circle).decode({ kind: 'circle', radius: 'big' });
// Err({ issues: [{ message: '"big" is not a valid number', path: ['radius'] }] })
Decoder for a union of alternatives. Tries each decoder in order and returns the first success. When all of them fail, it returns a summary issue stating that none matched, followed by every alternative's failure; issues that share a path are collapsed into a single "X or Y" message so competing alternatives don't read as conjunctive requirements.
When to use: reach for
oneOffor flat unions (primitives, literals) or "try these shapes in order". For other common unions there are more precise tools that produce cleaner errors:X | null-> nullableX | undefined-> optional