type-safe-json-decoder
Version:
Elm-inspired JSON decoder for typescript
232 lines (231 loc) • 17.6 kB
TypeScript
/**
* A Decoder represents a way to decode JSON into type T. Provided in this
* module are Decoders for primitive JSON types, as well as a set of
* higher-order Decoders that can be composed together to decode complex nested
* objects.
*/
export declare class Decoder<T> {
private fn;
private constructor(fn);
private static _ignore;
/**
* Attempt to decode some JSON input into a value of type T. Throws a
* descriptive error if the JSON input does not match the structure described
* by the Decoder.
* @param json A JSON encoded string.
* @returns A value of the type described by the Decoder.
*/
decodeJSON(json: string): T;
/**
* Attempt to decode a plain object into a value of type T. Throws a
* descriptive error if the object does not match the structure described
* by the decoder.
* @param object Any object.
* @returns A value of the type described by the Decoder.
*/
decodeAny(object: any): T;
}
/**
* Represents the property of an object to decode. See [object](#object) for
* more details.
*/
export declare type EntryDecoder<T> = [string, Decoder<T>];
/**
* @returns A Decoder that decodes a string.
*/
export declare function string(): Decoder<string>;
/**
* @returns A Decoder that decodes a number.
*/
export declare function number(): Decoder<number>;
/**
* @returns A Decoder that decodes a boolean.
*/
export declare function boolean(): Decoder<boolean>;
/**
* Decode a value and make sure the result equals another value. Useful for
* checking for `null`.
* ```typescript
* const decoder = object(
* ['shouldBeNull', equal(null)],
* (shouldBeNull) => ({shouldBeNull})
* )
* decoder.decodeJSON('{"shouldBeNull": null}')
* ```
* @param value Value that the input must equal (`===`).
* @returns A Decoder that decodes a value that equals the given value.
*/
export declare function equal<T>(value: T): Decoder<T>;
/**
* Decode an array using another decoder for each element. Can only decode
* arrays of a single type. If this feels like a limitation, you may be looking
* for [tuple](#tuple), or perhaps [andThen](#andthen) paired with TypeScript's
* union types.
* @param element A Decoder that decodes the element type of an array.
* @returns A Decoder that will decode an array of elements of the given type.
*/
export declare function array<T>(element: Decoder<T>): Decoder<T[]>;
/**
* Decode an object with the given fields and types.
* @param ad One or more EntryDecoders describing the object's fields.
* @param cons Constructor that uses the results from the given EntryDecoders.
* @returns A Decoder that will decode an object of the given type.
*/
export declare function object<T, A>(ad: EntryDecoder<A>, cons: (a: A) => T): Decoder<T>;
export declare function object<T, A, B>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cons: (a: A, b: B) => T): Decoder<T>;
export declare function object<T, A, B, C>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, cons: (a: A, b: B, c: C) => T): Decoder<T>;
export declare function object<T, A, B, C, D>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, cons: (a: A, b: B, c: C, d: D) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, cons: (a: A, b: B, c: C, d: D, e: E) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, cons: (a: A, b: B, c: C, d: D, e: E, f: F) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I, J>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, jd: EntryDecoder<J>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I, J, K>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, jd: EntryDecoder<J>, kd: EntryDecoder<K>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I, J, K, L>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, jd: EntryDecoder<J>, kd: EntryDecoder<K>, ld: EntryDecoder<L>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I, J, K, L, M>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, jd: EntryDecoder<J>, kd: EntryDecoder<K>, ld: EntryDecoder<L>, md: EntryDecoder<M>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M) => T): Decoder<T>;
export declare function object<T, A, B, C, D, E, F, G, H, I, J, K, L, M, N>(ad: EntryDecoder<A>, bd: EntryDecoder<B>, cd: EntryDecoder<C>, dd: EntryDecoder<D>, ed: EntryDecoder<E>, fd: EntryDecoder<F>, gd: EntryDecoder<G>, hd: EntryDecoder<H>, id: EntryDecoder<I>, jd: EntryDecoder<J>, kd: EntryDecoder<K>, ld: EntryDecoder<L>, md: EntryDecoder<M>, nd: EntryDecoder<N>, cons: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N) => T): Decoder<T>;
/**
* Maps a function over the value returned by a decoder. Useful for creating
* fancier objects from builtin types.
*
* ```typescript
* import Immutable from 'immutable'
*
* const decoder = map(
* Immutable.List,
* array(number())
* )
* ```
* @param tranform A function to apply to the decoded value.
* @returns A decoder that will apply the function after decoding the input.
*/
export declare function map<T1, T2>(transform: (v: T1) => T2, decoder: Decoder<T1>): Decoder<T2>;
/**
* Decodes a tuple from an array. If the length of the array is not known at
* compile time, you're probably looking for [array](#array).
* @param ad One or more decoders for each element of the array.
* @returns A decoder return a tuple containing each decoded element.
*/
export declare function tuple<A>(ad: Decoder<A>): Decoder<[A]>;
export declare function tuple<A, B>(ad: Decoder<A>, bd: Decoder<B>): Decoder<[A, B]>;
export declare function tuple<A, B, C>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder<[A, B, C]>;
export declare function tuple<A, B, C, D>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder<[A, B, C, D]>;
export declare function tuple<A, 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]>;
export declare function tuple<A, 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]>;
export declare function tuple<A, 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]>;
export declare function tuple<A, 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]>;
export declare function tuple<A, B, C, D, E, F, G, H, I>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>): Decoder<[A, B, C, D, E, F, G, H, I]>;
export declare function tuple<A, B, C, D, E, F, G, H, I, J>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>): Decoder<[A, B, C, D, E, F, G, H, I, J]>;
export declare function tuple<A, B, C, D, E, F, G, H, I, J, K>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>): Decoder<[A, B, C, D, E, F, G, H, I, J, K]>;
export declare function tuple<A, B, C, D, E, F, G, H, I, J, K, L>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>): Decoder<[A, B, C, D, E, F, G, H, I, J, K, L]>;
export declare function tuple<A, B, C, D, E, F, G, H, I, J, K, L, M>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>, md: Decoder<M>): Decoder<[A, B, C, D, E, F, G, H, I, J, K, L, M]>;
export declare function tuple<A, B, C, D, E, F, G, H, I, J, K, L, M, N>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>, md: Decoder<M>, nd: Decoder<N>): Decoder<[A, B, C, D, E, F, G, H, I, J, K, L, M, N]>;
/**
* Reaches into a nested data structure and decodes the value there. Useful if
* you only care about a single value in a nested data structure, or if you
* want to skip past a top level data key. Can perform lookups on nested arrays
* and objects.
* @param keyPath Path of key lookups into a nested object.
* @param decoder Decoder to use on the nested value.
* @returns A decoder that decodes the value of the nested object.
*/
export declare function at<T>(keyPath: Array<string | number>, decoder: Decoder<T>): Decoder<T>;
/**
* Try multiple decoders on a value. Useful when paired with union types, or as
* a way to provide a default value if something goes wrong. No decoders after
* the first successful one will be tried. In that way `oneOf` can be thought
* of a short circuit `OR` operator for decoders.
*
* The `first`/`rest` split is to make sure at least one decoder is specified.
* @param first First decoder to try.
* @param rest Fallback decoders to try in order if the first fails.
* @returns A decoder or throws an Error of no decoders succeeded.
*/
export declare function oneOf<T>(first: Decoder<T>, ...rest: Decoder<T>[]): Decoder<T>;
/**
* A decoder that always fails with the given error message.
* @param message Message to throw when this decoder is used.
* @returns Never since it always throws an error.
*/
export declare function fail(message: string): Decoder<never>;
/**
* A decoder that always succeeds with the given value.
* @param value Value that always gets returned when this decoder is used.
* @returns A decoder that always returns the given value.
*/
export declare function succeed<T>(value: T): Decoder<T>;
/**
* Intelligently decode a value based on the result of another decoder. Useful
* decoding on object whose type or structure is not immediately known. The
* first decoder can be used to look at part of the object, then the second one
* can can use the result of that decoder to decide on how to actually decode
* the object.
* @param ad First decoder to run against the value.
* @param cb Callback that receives the previous result and returns a decoder.
* @returns The decoder returned by from the callback function.
*/
export declare function andThen<A, B>(ad: Decoder<A>, cb: (a: A) => Decoder<B>): Decoder<B>;
/**
* Decode a union type. Given multiple decoders whose result type is a member
* of the union, try each one in order until one succeeds. Works similarly to
* [oneOf](#oneof), except that instead of the result being of single type, the
* result is the union of all given decoder types.
* @param ad A decoder for a member of the union.
* @param bd A decoder for another member of the union.
* @returns A decoder or throws an Error of no decoders succeeded.
*/
export declare function union<A, B>(ad: Decoder<A>, bd: Decoder<B>): Decoder<A | B>;
export declare function union<A, B, C>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder<A | B | C>;
export declare function union<A, B, C, D>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder<A | B | C | D>;
export declare function union<A, 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>;
export declare function union<A, 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>;
export declare function union<A, 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>;
export declare function union<A, 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>;
export declare function union<A, B, C, D, E, F, G, H, I>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>): Decoder<A | B | C | D | E | F | G | H | I>;
export declare function union<A, B, C, D, E, F, G, H, I, J>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>): Decoder<A | B | C | D | E | F | G | H | I | J>;
export declare function union<A, B, C, D, E, F, G, H, I, J, K>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>): Decoder<A | B | C | D | E | F | G | H | I | J | K>;
export declare function union<A, B, C, D, E, F, G, H, I, J, K, L>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>): Decoder<A | B | C | D | E | F | G | H | I | J | K | L>;
export declare function union<A, B, C, D, E, F, G, H, I, J, K, L, M>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>, md: Decoder<M>): Decoder<A | B | C | D | E | F | G | H | I | J | K | L | M>;
export declare function union<A, B, C, D, E, F, G, H, I, J, K, L, M, N>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>, ed: Decoder<E>, fd: Decoder<F>, gd: Decoder<G>, hd: Decoder<H>, id: Decoder<I>, jd: Decoder<J>, kd: Decoder<K>, ld: Decoder<L>, md: Decoder<M>, nd: Decoder<N>): Decoder<A | B | C | D | E | F | G | H | I | J | K | L | M | N>;
/**
* Decode a value with the decoder returned by the given function. This is
* useful if you need to decode a recursive data structure. TypeScript does not
* allow the direct use of variables within their definition:
* ```typescript
* interface Comment {
* msg: string
* replies: Comment[]
* }
* const decoder: Decoder<Comment> = object(
* ['msg', string()],
* ['replies', array(decoder)],
* (msg, replies) => ({msg, replies})
* )
// Block-scoped variable 'decoder' used before its declaration.
// Variable 'decoder' is used before being assigned.
* ```
* However, a variable can be used within its definition if it is not
* immediately evaluated, or in other words, wrapped in an anonymous function:
* ```typescript
* const decoder: Decoder<Comment> = object(
* ['msg', string()],
* ['replies', array(lazy(() => decoder))],
* (msg, replies) => ({msg, replies})
* )
* ```
* @param thunk A function that will return the decoder.
* @returns A decoder that lazily calls thunk to get the decoder when needed.
*/
export declare function lazy<T>(thunk: () => Decoder<T>): Decoder<T>;
/** Object with arbitrary keys and a single value type. Used by [dict](#dict).
*/
export declare type Dict<T> = {
[index: string]: T;
};
/**
* Decode an object with arbitrary keys. Values must be of the same type.
* @param value A Decoder that will be used to decode each value.
* @returns A Decoder will decode an object with arbitrary keys.
*/
export declare function dict<T>(value: Decoder<T>): Decoder<Dict<T>>;