@mojotech/json-type-validation > "decoder" > Decoder
Decoders transform json objects with unknown structure into known and verified forms. You can create objects of type Decoder<A> with either the primitive decoder functions, such as boolean() and string(), or by applying higher-order decoders to the primitives, such as array(boolean()) or dict(string()).
Each of the decoder functions are available both as a static method on Decoder and as a function alias -- for example the string decoder is defined at Decoder.string(), but is also aliased to string(). Using the function aliases exported with the library is recommended.
Decoder exposes a number of 'run' methods, which all decode json in the same way, but communicate success and failure in different ways. The map and andThen methods modify decoders without having to call a 'run' method.
Alternatively, the main decoder run() method returns an object of type Result<A, DecoderError>. This library provides a number of helper functions for dealing with the Result type, so you can do all the same things with a Result as with the decoder methods.
Decoder
- andThen
- map
- run
- runPromise
- runWithException
- where
- anyJson
- array
- boolean
- constant
- dict
- fail
- intersection
- lazy
- number
- object
- oneOf
- optional
- string
- succeed
- tuple
- union
- unknownJson
- valueAt
- withDefault
⊕ new Decoder(decode: function): Decoder
The Decoder class constructor is kept private to separate the internal decode function from the external run function. The distinction between the two functions is that decode returns a Partial<DecoderError> on failure, which contains an unfinished error report. When run is called on a decoder, the relevant series of decode calls is made, and then on failure the resulting Partial<DecoderError> is turned into a DecoderError by filling in the missing information.
While hiding the constructor may seem restrictive, leveraging the provided decoder combinators and helper functions such as andThen and map should be enough to build specialized decoders as needed.
Parameters:
| Param | Type |
|---|---|
| decode | function |
Returns: Decoder
● decode: function
▸(json: unknown): DecodeResult<A>
Parameters:
| Param | Type |
|---|---|
| json | unknown |
Returns: DecodeResult<A>
▸ andThenB(f: function): Decoder<B>
Chain together a sequence of decoders. The first decoder will run, and then the function will determine what decoder to run second. If the result of the first decoder succeeds then f will be applied to the decoded value. If it fails the error will propagate through.
This is a very powerful method -- it can act as both the map and where methods, can improve error messages for edge cases, and can be used to make a decoder for custom types.
Example of adding an error message:
const versionDecoder = valueAt(['version'], number());
const infoDecoder3 = object({a: boolean()});
const decoder = versionDecoder.andThen(version => {
switch (version) {
case 3:
return infoDecoder3;
default:
return fail(`Unable to decode info, version ${version} is not supported.`);
}
});
decoder.run({version: 3, a: true})
// => {ok: true, result: {a: true}}
decoder.run({version: 5, x: 'abc'})
// =>
// {
// ok: false,
// error: {... message: 'Unable to decode info, version 5 is not supported.'}
// }
Example of decoding a custom type:
// nominal type for arrays with a length of at least one
type NonEmptyArray<T> = T[] & { __nonEmptyArrayBrand__: void };
const nonEmptyArrayDecoder = <T>(values: Decoder<T>): Decoder<NonEmptyArray<T>> =>
array(values).andThen(arr =>
arr.length > 0
? succeed(createNonEmptyArray(arr))
: fail(`expected a non-empty array, got an empty array`)
);
Type parameters:
Parameters:
| Param | Type |
|---|---|
| f | function |
Returns: Decoder<B>
▸ mapB(f: function): Decoder<B>
Construct a new decoder that applies a transformation to the decoded result. If the decoder succeeds then f will be applied to the value. If it fails the error will propagated through.
Example:
number().map(x => x * 5).run(10)
// => {ok: true, result: 50}
Type parameters:
Parameters:
| Param | Type |
|---|---|
| f | function |
Returns: Decoder<B>
▸ run(json: unknown): RunResult<A>
Run the decoder and return a Result with either the decoded value or a DecoderError containing the json input, the location of the error, and the error message.
Examples:
number().run(12)
// => {ok: true, result: 12}
string().run(9001)
// =>
// {
// ok: false,
// error: {
// kind: 'DecoderError',
// input: 9001,
// at: 'input',
// message: 'expected a string, got 9001'
// }
// }
Parameters:
| Param | Type |
|---|---|
| json | unknown |
Returns: RunResult<A>
▸ runPromise(json: unknown): Promise<A>
Run the decoder as a Promise.
Parameters:
| Param | Type |
|---|---|
| json | unknown |
Returns: Promise<A>
▸ runWithException(json: unknown): A
Run the decoder and return the value on success, or throw an exception with a formatted error string.
Parameters:
| Param | Type |
|---|---|
| json | unknown |
Returns: A
▸ where(test: function, errorMessage: string): Decoder<A>
Add constraints to a decoder without changing the resulting type. The test argument is a predicate function which returns true for valid inputs. When test fails on an input, the decoder fails with the given errorMessage.
const chars = (length: number): Decoder<string> =>
string().where(
(s: string) => s.length === length,
`expected a string of length ${length}`
);
chars(5).run('12345')
// => {ok: true, result: '12345'}
chars(2).run('HELLO')
// => {ok: false, error: {... message: 'expected a string of length 2'}}
chars(12).run(true)
// => {ok: false, error: {... message: 'expected a string, got a boolean'}}
Parameters:
| Param | Type |
|---|---|
| test | function |
| errorMessage | string |
Returns: Decoder<A>
▸ anyJson(): Decoder<any>
Escape hatch to bypass validation. Always succeeds and types the result as any. Useful for defining decoders incrementally, particularly for complex objects.
Example:
interface User {
name: string;
complexUserData: ComplexType;
}
const userDecoder: Decoder<User> = object({
name: string(),
complexUserData: anyJson()
});
Returns: Decoder<any>
▸ array(): Decoder<unknown[]>
▸ arrayA(decoder: Decoder<A>): Decoder<A[]>
Decoder for json arrays. Runs decoder on each array element, and succeeds if all elements are successfully decoded. If no decoder argument is provided then the outer array part of the json is validated but not the contents, typing the result as unknown[].
To decode a single value that is inside of an array see valueAt.
Examples:
array(number()).run([1, 2, 3])
// => {ok: true, result: [1, 2, 3]}
array(array(boolean())).run([[true], [], [true, false, false]])
// => {ok: true, result: [[true], [], [true, false, false]]}
const validNumbersDecoder = array()
.map((arr: unknown[]) => arr.map(number().run))
.map(Result.successes)
validNumbersDecoder.run([1, true, 2, 3, 'five', 4, []])
// {ok: true, result: [1, 2, 3, 4]}
validNumbersDecoder.run([false, 'hi', {}])
// {ok: true, result: []}
validNumbersDecoder.run(false)
// {ok: false, error: {..., message: "expected an array, got a boolean"}}
Returns: Decoder<unknown[]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | Decoder<A> |
Returns: Decoder<A[]>
▸ boolean(): Decoder<boolean>
Decoder primitive that validates booleans, and fails on all other input.
Returns: Decoder<boolean>
▸ constant(value: true): Decoder<true>
▸ constant(value: false): Decoder<false>
▸ constantA(value: A): Decoder<A>
Decoder primitive that only matches on exact values.
Note that constant('string to match') returns a Decoder<string> which fails if the input is not equal to 'string to match'. In many cases this is sufficient, but in some situations typescript requires that the decoder type be a type-literal. In such a case you must provide the type parameter, which looks like constant<'string to match'>('string to match').
Providing the type parameter is only necessary for type-literal strings and numbers, as detailed by this table:
| Decoder | Type |
| ---------------------------- | ---------------------|
| constant(true) | Decoder<true> |
| constant(false) | Decoder<false> |
| constant(null) | Decoder<null> |
| constant('alaska') | Decoder<string> |
| constant<'alaska'>('alaska') | Decoder<'alaska'> |
| constant(50) | Decoder<number> |
| constant<50>(50) | Decoder<50> |
| constant([1,2,3]) | Decoder<number[]> |
| constant<[1,2,3]>([1,2,3]) | Decoder<[1,2,3]> |
| constant({x: 't'}) | Decoder<{x: string}> |
| constant<{x: 't'}>({x: 't'}) | Decoder<{x: 't'}> |
One place where this happens is when a type-literal is in an interface:
interface Bear {
kind: 'bear';
isBig: boolean;
}
const bearDecoder1: Decoder<Bear> = object({
kind: constant('bear'),
isBig: boolean()
});
// Type 'Decoder<{ kind: string; isBig: boolean; }>' is not assignable to
// type 'Decoder<Bear>'. Type 'string' is not assignable to type '"bear"'.
const bearDecoder2: Decoder<Bear> = object({
kind: constant<'bear'>('bear'),
isBig: boolean()
});
// no compiler errors
Another is in type-literal unions:
type animal = 'bird' | 'bear';
const animalDecoder1: Decoder<animal> = union(
constant('bird'),
constant('bear')
);
// Type 'Decoder<string>' is not assignable to type 'Decoder<animal>'.
// Type 'string' is not assignable to type 'animal'.
const animalDecoder2: Decoder<animal> = union(
constant<'bird'>('bird'),
constant<'bear'>('bear')
);
// no compiler errors
Parameters:
| Param | Type |
|---|---|
| value | true |
Returns: Decoder<true>
Parameters:
| Param | Type |
|---|---|
| value | false |
Returns: Decoder<false>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| value | A |
Returns: Decoder<A>
▸ dictA(decoder: Decoder<A>): Decoder<Record<string, A>>
Decoder for json objects where the keys are unknown strings, but the values should all be of the same type.
Example:
dict(number()).run({chocolate: 12, vanilla: 10, mint: 37});
// => {ok: true, result: {chocolate: 12, vanilla: 10, mint: 37}}
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | Decoder<A> |
Returns: Decoder<Record<string, A>>
▸ failA(errorMessage: string): Decoder<A>
Decoder that ignores the input json and always fails with errorMessage.
Type parameters:
Parameters:
| Param | Type |
|---|---|
| errorMessage | string |
Returns: Decoder<A>
▸ intersectionA,B(ad: Decoder<A>, bd: Decoder<B>): Decoder< A & B>
▸ intersectionA,B,C(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder< A & B & C>
▸ intersectionA,B,C,D(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder< A & B & C & D>
▸ intersectionA,B,C,D,E(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>): Decoder< A & B & C & D & E>
▸ intersectionA,B,C,D,E,F(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>): Decoder< A & B & C & D & E & F>
▸ intersectionA,B,C,D,E,F,G(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>): Decoder< A & B & C & D & E & F & G>
▸ intersectionA,B,C,D,E,F,G,H(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>): Decoder< A & B & C & D & E & F & G & H>
Combines 2-8 object decoders into a decoder for the intersection of all the objects.
Example:
interface Pet {
name: string;
maxLegs: number;
}
interface Cat extends Pet {
evil: boolean;
}
const petDecoder: Decoder<Pet> = object({name: string(), maxLegs: number()});
const catDecoder: Decoder<Cat> = intersection(petDecoder, object({evil: boolean()}));
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
Returns: Decoder< A & B>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
Returns: Decoder< A & B & C>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
Returns: Decoder< A & B & C & D>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
Returns: Decoder< A & B & C & D & E>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
Returns: Decoder< A & B & C & D & E & F>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
| gd | Decoder<G> |
Returns: Decoder< A & B & C & D & E & F & G>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
| gd | Decoder<G> |
| hd | Decoder<H> |
Returns: Decoder< A & B & C & D & E & F & G & H>
▸ lazyA(mkDecoder: function): Decoder<A>
Decoder that allows for validating recursive data structures. Unlike with functions, decoders assigned to variables can't reference themselves before they are fully defined. We can avoid prematurely referencing the decoder by wrapping it in a function that won't be called until use, at which point the decoder has been defined.
Example:
interface Comment {
msg: string;
replies: Comment[];
}
const decoder: Decoder<Comment> = object({
msg: string(),
replies: lazy(() => array(decoder))
});
Type parameters:
Parameters:
| Param | Type |
|---|---|
| mkDecoder | function |
Returns: Decoder<A>
▸ number(): Decoder<number>
Decoder primitive that validates numbers, and fails on all other input.
Returns: Decoder<number>
▸ object(): Decoder<Record<string, unknown>>
▸ objectA(decoders: DecoderObject<A>): Decoder<A>
An higher-order decoder that runs decoders on specified fields of an object, and returns a new object with those fields. If object is called with no arguments, then the outer object part of the json is validated but not the contents, typing the result as a record where all keys have a value of type unknown.
The optional and constant decoders are particularly useful for decoding objects that match typescript interfaces.
To decode a single field that is inside of an object see valueAt.
Example:
object({x: number(), y: number()}).run({x: 5, y: 10})
// => {ok: true, result: {x: 5, y: 10}}
object().map(Object.keys).run({n: 1, i: [], c: {}, e: 'e'})
// => {ok: true, result: ['n', 'i', 'c', 'e']}
Returns: Decoder<Record<string, unknown>>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoders | DecoderObject<A> |
Returns: Decoder<A>
▸ oneOfA(...decoders: Decoder<A>[]): Decoder<A>
Decoder that attempts to run each decoder in decoders and either succeeds with the first successful decoder, or fails after all decoders have failed.
Note that oneOf expects the decoders to all have the same return type, while union creates a decoder for the union type of all the input decoders.
Examples:
oneOf(string(), number().map(String))
oneOf(constant('start'), constant('stop'), succeed('unknown'))
Type parameters:
Parameters:
| Param | Type |
|---|---|
Rest decoders |
Decoder<A>[] |
Returns: Decoder<A>
▸ optionalA(decoder: Decoder<A>): Decoder< undefined | A>
Decoder for values that may be undefined. This is primarily helpful for decoding interfaces with optional fields.
Example:
interface User {
id: number;
isOwner?: boolean;
}
const decoder: Decoder<User> = object({
id: number(),
isOwner: optional(boolean())
});
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | Decoder<A> |
Returns: Decoder< undefined | A>
▸ string(): Decoder<string>
Decoder primitive that validates strings, and fails on all other input.
Returns: Decoder<string>
▸ succeedA(fixedValue: A): Decoder<A>
Decoder that ignores the input json and always succeeds with fixedValue.
Type parameters:
Parameters:
| Param | Type |
|---|---|
| fixedValue | A |
Returns: Decoder<A>
▸ tupleA(decoder: [Decoder<A>]): Decoder<[A]>
▸ tupleA,B(decoder: [Decoder<A>, Decoder<B>]): Decoder<[A, B]>
▸ tupleA,B,C(decoder: [Decoder<A>, Decoder<B>, Decoder<C>]): Decoder<[A, B, C]>
▸ tupleA,B,C,D(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>]): Decoder<[A, B, C, D]>
▸ tupleA,B,C,D,E(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>]): Decoder<[A, B, C, D, E]>
▸ tupleA,B,C,D,E,F(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>]): Decoder<[A, B, C, D, E, F]>
▸ tupleA,B,C,D,E,F,G(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>, Decoder<G>]): Decoder<[A, B, C, D, E, F, G]>
▸ tupleA,B,C,D,E,F,G,H(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>, Decoder<G>, Decoder<H>]): Decoder<[A, B, C, D, E, F, G, H]>
Decoder for fixed-length arrays, aka Tuples.
Supports up to 8-tuples.
Example:
tuple([number(), number(), string()]).run([5, 10, 'px'])
// => {ok: true, result: [5, 10, 'px']}
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>] |
Returns: Decoder<[A]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>] |
Returns: Decoder<[A, B]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>] |
Returns: Decoder<[A, B, C]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>] |
Returns: Decoder<[A, B, C, D]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>] |
Returns: Decoder<[A, B, C, D, E]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>] |
Returns: Decoder<[A, B, C, D, E, F]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>, Decoder<G>] |
Returns: Decoder<[A, B, C, D, E, F, G]>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| decoder | [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>, Decoder<F>, Decoder<G>, Decoder<H>] |
Returns: Decoder<[A, B, C, D, E, F, G, H]>
▸ unionA,B(ad: Decoder<A>, bd: Decoder<B>): Decoder< A | B>
▸ unionA,B,C(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder< A | B | C>
▸ unionA,B,C,D(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder< A | B | C | D>
▸ unionA,B,C,D,E(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>): Decoder< A | B | C | D | E>
▸ unionA,B,C,D,E,F(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>): Decoder< A | B | C | D | E | F>
▸ unionA,B,C,D,E,F,G(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>): Decoder< A | B | C | D | E | F | G>
▸ unionA,B,C,D,E,F,G,H(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>): Decoder< A | B | C | D | E | F | G | H>
Combines 2-8 decoders of disparate types into a decoder for the union of all the types.
If you need more than 8 variants for your union, it's possible to use oneOf in place of union as long as you annotate every decoder with the union type.
Example:
type C = {a: string} | {b: number};
const unionDecoder: Decoder<C> = union(object({a: string()}), object({b: number()}));
const oneOfDecoder: Decoder<C> = oneOf(object<C>({a: string()}), object<C>({b: number()}));
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
Returns: Decoder< A | B>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
Returns: Decoder< A | B | C>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
Returns: Decoder< A | B | C | D>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
Returns: Decoder< A | B | C | D | E>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
Returns: Decoder< A | B | C | D | E | F>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
| gd | Decoder<G> |
Returns: Decoder< A | B | C | D | E | F | G>
Type parameters:
Parameters:
| Param | Type |
|---|---|
| ad | Decoder<A> |
| bd | Decoder<B> |
| cd | Decoder<C> |
| dd | Decoder<D> |
| ed | Decoder<E> |
| fd | Decoder<F> |
| gd | Decoder<G> |
| hd | Decoder<H> |
Returns: Decoder< A | B | C | D | E | F | G | H>
▸ unknownJson(): Decoder<unknown>
Decoder identity function which always succeeds and types the result as unknown.
Returns: Decoder<unknown>
▸ valueAtA(paths: ( string | number)[], decoder: Decoder<A>): Decoder<A>
Decoder that pulls a specific field out of a json structure, instead of decoding and returning the full structure. The paths array describes the object keys and array indices to traverse, so that values can be pulled out of a nested structure.
Example:
const decoder = valueAt(['a', 'b', 0], string());
decoder.run({a: {b: ['surprise!']}})
// => {ok: true, result: 'surprise!'}
decoder.run({a: {x: 'cats'}})
// => {ok: false, error: {... at: 'input.a.b[0]' message: 'path does not exist'}}
Note that the decoder is ran on the value found at the last key in the path, even if the last key is not found. This allows the optional decoder to succeed when appropriate.
const optionalDecoder = valueAt(['a', 'b', 'c'], optional(string()));
optionalDecoder.run({a: {b: {c: 'surprise!'}}})
// => {ok: true, result: 'surprise!'}
optionalDecoder.run({a: {b: 'cats'}})
// => {ok: false, error: {... at: 'input.a.b.c' message: 'expected an object, got "cats"'}
optionalDecoder.run({a: {b: {z: 1}}})
// => {ok: true, result: undefined}
Type parameters:
Parameters:
| Param | Type |
|---|---|
| paths | ( string | number)[] |
| decoder | Decoder<A> |
Returns: Decoder<A>
▸ withDefaultA(defaultValue: A, decoder: Decoder<A>): Decoder<A>
Decoder that always succeeds with either the decoded value, or a fallback default value.
Type parameters:
Parameters:
| Param | Type |
|---|---|
| defaultValue | A |
| decoder | Decoder<A> |
Returns: Decoder<A>