master 091844b153c2 cached
34 files
135.3 KB
40.3k tokens
40 symbols
1 requests
Download .txt
Repository: mojotech/json-type-validation
Branch: master
Commit: 091844b153c2
Files: 34
Total size: 135.3 KB

Directory structure:
gitextract_0gr7gt1_/

├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .travis.yml
├── DOCS.md
├── LICENSE
├── README.md
├── bin/
│   └── jtv
├── docs/
│   ├── README.md
│   ├── classes/
│   │   └── _decoder_.decoder.md
│   ├── interfaces/
│   │   ├── _decoder_.decodererror.md
│   │   ├── _result_.err.md
│   │   └── _result_.ok.md
│   └── modules/
│       ├── _combinators_.md
│       ├── _decoder_.md
│       ├── _index_.md
│       └── _result_.md
├── nix-files/
│   ├── default.nix
│   ├── nixpkgs.nix
│   └── shell.nix
├── package.json
├── rollup.config.ts
├── src/
│   ├── combinators.ts
│   ├── decoder.ts
│   ├── index.ts
│   └── result.ts
├── test/
│   ├── json-decode.test.ts
│   ├── phone-example.test.ts
│   ├── tagged-json-example.test.ts
│   └── user-example.test.ts
├── tsconfig-test.json
├── tsconfig.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules
coverage
.nyc_output
.DS_Store
*.log
.vscode
.idea
dist
compiled
.awcache
.rpt2_cache
gc-roots


================================================
FILE: .npmignore
================================================
.git/
.rpt2_cache/
bin/
coverage/
nix-files/
node_modules/
src/
test/
.gitignore
.prettierrc
.travis.yml
rollup.config.ts
tags
tsconfig-test.json
tsconfig.json
tslint.json
yarn.lock


================================================
FILE: .prettierignore
================================================
package.json
dist/


================================================
FILE: .prettierrc
================================================
printWidth: 100
tabWidth: 2
useTabs: false
semi: true
singleQuote: true
trailingComma: none
bracketSpacing: false
arrowParens: avoid
parser: typescript


================================================
FILE: .travis.yml
================================================
language: node_js
cache:
  yarn: true
  directories:
    - node_modules
notifications:
  email: false
node_js:
  - node
script:
  - npm run test:prod && npm run build
after_success:
  - npm run report-coverage


================================================
FILE: DOCS.md
================================================
# Documentation

[Documentation](https://github.com/mojotech/json-type-validation/tree/master/docs).

The best places to start are with the examples in the `test/` directory, and the
documentation for the
[Decoder class](https://github.com/mojotech/json-type-validation/blob/master/docs/classes/_decoder_.decoder.md).
At some point you may need documentation for dealing with the
[Result type](https://github.com/mojotech/json-type-validation/blob/master/docs/modules/_result_.md).

### Type Parameters

Many of the decoder functions take an optional type parameter which determines
the type of the decoded value. In most cases typescript successfully infers
these types, although some specific decoders include documentation for
situations where the type is necessary (see the `constant` and `union`
decoders). You may still find that including the type parameter improves type
inference in situations where typescript's error messages are particularly
unhelpful.

As an example, a decoder for the `Pet` interface can be typechecked just as
effectively using the type parameter as with the `Decoder<Pet>` annotation.
```
const petDecoder = object<Pet>({
  name: string(),
  species: string(),
  age: optional(number()),
  isCute: optional(boolean())
})
```

### Combinators

This library uses the [combinator pattern](https://wiki.haskell.org/Combinator_pattern)
to build decoders. The decoder primitives `string`, `number`, `boolean`,
`anyJson`, `constant`, `succeed`, and `fail` act as decoder building blocks that
each perform a simple decoding operation. The decoder combinators `object`,
`array`, `dict`, `optional`, `oneOf`, `union`, `withDefault`, `valueAt`, and
`lazy` take decoders as arguments, and combined the decoders into more
complicated structures. You can think of your own user-defined decoders as an
extension of these composable units.


================================================
FILE: LICENSE
================================================
Copyright (c) 2018 Elias Mulhall

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# JSON Type Validation

A [TypeScript](https://www.typescriptlang.org/) library to perform type checking and validation on untyped JSON data at runtime.

This library owes thanks to:

- [JsonDecoder](https://github.com/aische/JsonDecoder) by Daniel van den Eijkel
- [Type-safe JSON Decoder](https://github.com/ooesili/type-safe-json-decoder) by Wesley Merkel
- The Elm [Json.Decode](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode) API

## Installation
```
npm i @mojotech/json-type-validation
```
Projects using `< typescript@3.0.1` will need a polyfill for the `unknown`
type, such as [unknown-ts](https://www.npmjs.com/package/unknown-ts).

## Motivation

Let's say we're creating a web app for our pet sitting business, and we've
picked TypeScript as one of our core technologies. This is a great choice
because the extra stability and type safety that TypeScript provides is really
going to help us market our business.

We've defined the data we need to track about each client's pet:

```typescript
interface Pet {
  name: string;
  species: string;
  age?: number;
  isCute?: boolean;
}
```

And we've got some data about current client's pets which is stored as JSON:

```typescript
const croc: Pet = JSON.parse('{"name":"Lyle","species":"Crocodile","isCute":true}')
const moose: Pet = JSON.parse('{"name":"Bullwinkle","age":59}')
```

But that can't be right -- our data for `moose` is missing information required
for the `Pet` interface, but TypeScript compiles the code just fine!

Of course this isn't an issue with TypeScript, but with our own type
annotations. In TypeScript `JSON.parse` has a return type of `any`, which pushes
the responsibility of verifying the type of data onto the user. By assuming that
all of our data is correctly formed, we've left ourselves open to unexpected
errors at runtime.

Unfortunately TypeScript doesn't provide a good built-in way to deal with this
issue. Providing run-time type information is one of TypeScript's
[non-goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals#non-goals),
and our web app is too important to risk using a forked version of TypeScript
with that added functionality.
[Type guards](https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html)
work, but are limited in that they circumvent type inference instead of working
with it, and can be cumbersome to write.

With `json-type-validation` we can define decoders that validate untyped json
input. Decoders are concise, composable, and typecheck against our defined types
and interfaces.

```typescript
import {Decoder, object, string, optional, number, boolean} from '@mojotech/json-type-validation'

const petDecoder: Decoder<Pet> = object({
  name: string(),
  species: string(),
  age: optional(number()),
  isCute: optional(boolean())
})
```

Finally, we can choose from a number of decoding methods to validate json and
report success or failure. When some json input fails validation the decoder
clearly shows how the data was malformed.

```typescript
const lyle: Pet = petDecoder.runWithException(croc)

const bullwinkle: Pet = petDecoder.runWithException(moose)
// Throws the exception:
// `Input: {"name":"Bullwinkle","age":59}
//  Failed at input: the key 'species' is required but was not present`
```

## Documentation

[Documentation](https://github.com/mojotech/json-type-validation/tree/master/docs).

## Building

### With Nix

There exists some [Nix](https://nixos.org/nix) infrastructure that can be used
to reproduce a build environment exactly. A helper shell script lives at
`bin/jtv` that you can use to enter environments for multiple uses.
You'll need to follow the directions on the Nix website to install and use the
Nix package manager.

* To enter a shell suitable for building the library run `./bin/jtv
  build-shell`. This will leave you in the root of the project and automatically
  install any project and npm dependencies. You can run further yarn commands
  here.
* To build the library for distribution and exit you can run `./bin/jtv distribute`.
* To enter a build shell and run the build process, watching for changes, run
  `./bin/jtv build-watch`.
* To run an arbitrary command in a build environment use `./bin/jtv run
  COMMAND`. For example, `./bin/jtv run yarn test` will run the tests and exit.


================================================
FILE: bin/jtv
================================================
#!/usr/bin/env bash

SCRIPTNAME=$(basename $0)
DIRNAME=$(dirname $0)
MODE=$1

shift

print_help() {
    echo "Usage: $SCRIPTNAME MODE"
    echo "Enter a shell with all dependencies required for MODE."
    echo "MODE is one of:"
    echo "  build-shell - enter a shell for building the library"
    echo "  build-watch - enter a build shell and run \`yarn start\`"
    echo "  distribute - build the library and exist"
    echo "  run COMMAND - enter a build shell and run the specified command"
    echo "  help, --help, -h - display this help message"
}
if [ "$MODE" = "help" -o "$MODE" = "--help" -o "$MODE" = "-h" ]; then
    print_help
    exit 0
fi

if [ "$MODE" = "build-shell" ]; then
    echo "Starting build shell..."
    # --add-root, --indirect place a garbage collection root outside of the main
    # nix store directory. This allows you to run nix-collect-garbage without
    # collecting the dependencies for this package. To collect the dependencies
    # for this package, delete the roots in gc-roots.
    # --pure limits the generated shell to only those dependencies specified in
    # the nix file.
    nix-shell --pure --add-root $DIRNAME/../gc-roots/json-type-validation.drv --indirect $DIRNAME/../nix-files/shell.nix
elif [ "$MODE" = "build-watch" ]; then
    echo "Starting build watcher..."
    nix-shell --pure --add-root $DIRNAME/../gc-roots/json-type-validation.drv --indirect $DIRNAME/../nix-files/shell.nix --run "yarn start"
elif [ "$MODE" = "distribute" ]; then
    echo "Building library for distribution..."
    nix-shell --pure --add-root $DIRNAME/../gc-roots/json-type-validation.drv --indirect $DIRNAME/../nix-files/shell.nix --run "yarn build"

elif [ "$MODE" = "run" ]; then
    echo "Running \`$@\` in build environment..."
    nix-shell --pure --add-root $DIRNAME/../gc-roots/json-type-validation.drv --indirect $DIRNAME/../nix-files/shell.nix --run "$*"
else
    echo "Must specify MODE!"
    print_help
    exit 1
fi


================================================
FILE: docs/README.md
================================================

Documentation
=============

[Documentation](https://github.com/mojotech/json-type-validation/tree/master/docs).

The best places to start are with the examples in the `test/` directory, and the documentation for the [Decoder class](https://github.com/mojotech/json-type-validation/blob/master/docs/classes/_decoder_.decoder.md). At some point you may need documentation for dealing with the [Result type](https://github.com/mojotech/json-type-validation/blob/master/docs/modules/_result_.md).

### Type Parameters

Many of the decoder functions take an optional type parameter which determines the type of the decoded value. In most cases typescript successfully infers these types, although some specific decoders include documentation for situations where the type is necessary (see the `constant` and `union` decoders). You may still find that including the type parameter improves type inference in situations where typescript's error messages are particularly unhelpful.

As an example, a decoder for the `Pet` interface can be typechecked just as effectively using the type parameter as with the `Decoder<Pet>` annotation.

```
const petDecoder = object<Pet>({
  name: string(),
  species: string(),
  age: optional(number()),
  isCute: optional(boolean())
})
```

### Combinators

This library uses the [combinator pattern](https://wiki.haskell.org/Combinator_pattern) to build decoders. The decoder primitives `string`, `number`, `boolean`, `anyJson`, `constant`, `succeed`, and `fail` act as decoder building blocks that each perform a simple decoding operation. The decoder combinators `object`, `array`, `dict`, `optional`, `oneOf`, `union`, `withDefault`, `valueAt`, and `lazy` take decoders as arguments, and combined the decoders into more complicated structures. You can think of your own user-defined decoders as an extension of these composable units.

## Index

### External modules

* ["combinators"](modules/_combinators_.md)
* ["decoder"](modules/_decoder_.md)
* ["index"](modules/_index_.md)
* ["result"](modules/_result_.md)

---



================================================
FILE: docs/classes/_decoder_.decoder.md
================================================
[@mojotech/json-type-validation](../README.md) > ["decoder"](../modules/_decoder_.md) > [Decoder](../classes/_decoder_.decoder.md)

# Class: 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.

## Type parameters
#### A 
## Hierarchy

**Decoder**

## Index

### Constructors

* [constructor](_decoder_.decoder.md#constructor)

### Properties

* [decode](_decoder_.decoder.md#decode)

### Methods

* [andThen](_decoder_.decoder.md#andthen)
* [map](_decoder_.decoder.md#map)
* [run](_decoder_.decoder.md#run)
* [runPromise](_decoder_.decoder.md#runpromise)
* [runWithException](_decoder_.decoder.md#runwithexception)
* [where](_decoder_.decoder.md#where)
* [anyJson](_decoder_.decoder.md#anyjson)
* [array](_decoder_.decoder.md#array)
* [boolean](_decoder_.decoder.md#boolean)
* [constant](_decoder_.decoder.md#constant)
* [dict](_decoder_.decoder.md#dict)
* [fail](_decoder_.decoder.md#fail)
* [intersection](_decoder_.decoder.md#intersection)
* [lazy](_decoder_.decoder.md#lazy)
* [number](_decoder_.decoder.md#number)
* [object](_decoder_.decoder.md#object)
* [oneOf](_decoder_.decoder.md#oneof)
* [optional](_decoder_.decoder.md#optional)
* [string](_decoder_.decoder.md#string)
* [succeed](_decoder_.decoder.md#succeed)
* [tuple](_decoder_.decoder.md#tuple)
* [union](_decoder_.decoder.md#union)
* [unknownJson](_decoder_.decoder.md#unknownjson)
* [valueAt](_decoder_.decoder.md#valueat)
* [withDefault](_decoder_.decoder.md#withdefault)

---

## Constructors

<a id="constructor"></a>

### `<Private>` constructor

⊕ **new Decoder**(decode: *`function`*): [Decoder](_decoder_.decoder.md)

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](_decoder_.decoder.md)

___

## Properties

<a id="decode"></a>

### `<Private>` decode

**● decode**: *`function`*

#### Type declaration
▸(json: *`unknown`*): `DecodeResult`<`A`>

**Parameters:**

| Param | Type |
| ------ | ------ |
| json | `unknown` |

**Returns:** `DecodeResult`<`A`>

___

## Methods

<a id="andthen"></a>

###  andThen

▸ **andThen**B(f: *`function`*): [Decoder](_decoder_.decoder.md)<`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:**

#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |

**Returns:** [Decoder](_decoder_.decoder.md)<`B`>

___
<a id="map"></a>

###  map

▸ **map**B(f: *`function`*): [Decoder](_decoder_.decoder.md)<`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:**

#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |

**Returns:** [Decoder](_decoder_.decoder.md)<`B`>

___
<a id="run"></a>

###  run

▸ **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`>

___
<a id="runpromise"></a>

###  runPromise

▸ **runPromise**(json: *`unknown`*): `Promise`<`A`>

Run the decoder as a `Promise`.

**Parameters:**

| Param | Type |
| ------ | ------ |
| json | `unknown` |

**Returns:** `Promise`<`A`>

___
<a id="runwithexception"></a>

###  runWithException

▸ **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`

___
<a id="where"></a>

###  where

▸ **where**(test: *`function`*, errorMessage: *`string`*): [Decoder](_decoder_.decoder.md)<`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](_decoder_.decoder.md)<`A`>

___
<a id="anyjson"></a>

### `<Static>` anyJson

▸ **anyJson**(): [Decoder](_decoder_.decoder.md)<`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](_decoder_.decoder.md)<`any`>

___
<a id="array"></a>

### `<Static>` array

▸ **array**(): [Decoder](_decoder_.decoder.md)<`unknown`[]>

▸ **array**A(decoder: *[Decoder](_decoder_.decoder.md)<`A`>*): [Decoder](_decoder_.decoder.md)<`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](_decoder_.decoder.md)<`unknown`[]>

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [Decoder](_decoder_.decoder.md)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`[]>

___
<a id="boolean"></a>

### `<Static>` boolean

▸ **boolean**(): [Decoder](_decoder_.decoder.md)<`boolean`>

Decoder primitive that validates booleans, and fails on all other input.

**Returns:** [Decoder](_decoder_.decoder.md)<`boolean`>

___
<a id="constant"></a>

### `<Static>` constant

▸ **constant**(value: *`true`*): [Decoder](_decoder_.decoder.md)<`true`>

▸ **constant**(value: *`false`*): [Decoder](_decoder_.decoder.md)<`false`>

▸ **constant**A(value: *`A`*): [Decoder](_decoder_.decoder.md)<`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](_decoder_.decoder.md)<`true`>

**Parameters:**

| Param | Type |
| ------ | ------ |
| value | `false` |

**Returns:** [Decoder](_decoder_.decoder.md)<`false`>

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| value | `A` |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="dict"></a>

### `<Static>` dict

▸ **dict**A(decoder: *[Decoder](_decoder_.decoder.md)<`A`>*): [Decoder](_decoder_.decoder.md)<`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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [Decoder](_decoder_.decoder.md)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)<`Record`<`string`, `A`>>

___
<a id="fail"></a>

### `<Static>` fail

▸ **fail**A(errorMessage: *`string`*): [Decoder](_decoder_.decoder.md)<`A`>

Decoder that ignores the input json and always fails with `errorMessage`.

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| errorMessage | `string` |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="intersection"></a>

### `<Static>` intersection

▸ **intersection**A,B(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*): [Decoder](_decoder_.decoder.md)< `A` & `B`>

▸ **intersection**A,B,C(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*): [Decoder](_decoder_.decoder.md)< `A` & `B` & `C`>

▸ **intersection**A,B,C,D(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*): [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D`>

▸ **intersection**A,B,C,D,E(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*): [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E`>

▸ **intersection**A,B,C,D,E,F(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*): [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E` & `F`>

▸ **intersection**A,B,C,D,E,F,G(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*, gd: *[Decoder](_decoder_.decoder.md)<`G`>*): [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E` & `F` & `G`>

▸ **intersection**A,B,C,D,E,F,G,H(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*, gd: *[Decoder](_decoder_.decoder.md)<`G`>*, hd: *[Decoder](_decoder_.decoder.md)<`H`>*): [Decoder](_decoder_.decoder.md)< `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:**

#### A 
#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B`>

**Type parameters:**

#### A 
#### B 
#### C 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E` & `F`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |
| gd | [Decoder](_decoder_.decoder.md)<`G`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E` & `F` & `G`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
#### H 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |
| gd | [Decoder](_decoder_.decoder.md)<`G`> |
| hd | [Decoder](_decoder_.decoder.md)<`H`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` & `B` & `C` & `D` & `E` & `F` & `G` & `H`>

___
<a id="lazy"></a>

### `<Static>` lazy

▸ **lazy**A(mkDecoder: *`function`*): [Decoder](_decoder_.decoder.md)<`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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| mkDecoder | `function` |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="number"></a>

### `<Static>` number

▸ **number**(): [Decoder](_decoder_.decoder.md)<`number`>

Decoder primitive that validates numbers, and fails on all other input.

**Returns:** [Decoder](_decoder_.decoder.md)<`number`>

___
<a id="object"></a>

### `<Static>` object

▸ **object**(): [Decoder](_decoder_.decoder.md)<`Record`<`string`, `unknown`>>

▸ **object**A(decoders: *[DecoderObject](../modules/_decoder_.md#decoderobject)<`A`>*): [Decoder](_decoder_.decoder.md)<`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](_decoder_.decoder.md)<`Record`<`string`, `unknown`>>

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoders | [DecoderObject](../modules/_decoder_.md#decoderobject)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="oneof"></a>

### `<Static>` oneOf

▸ **oneOf**A(...decoders: *[Decoder](_decoder_.decoder.md)<`A`>[]*): [Decoder](_decoder_.decoder.md)<`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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| `Rest` decoders | [Decoder](_decoder_.decoder.md)<`A`>[] |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="optional"></a>

### `<Static>` optional

▸ **optional**A(decoder: *[Decoder](_decoder_.decoder.md)<`A`>*): [Decoder](_decoder_.decoder.md)< `undefined` &#124; `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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [Decoder](_decoder_.decoder.md)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `undefined` &#124; `A`>

___
<a id="string"></a>

### `<Static>` string

▸ **string**(): [Decoder](_decoder_.decoder.md)<`string`>

Decoder primitive that validates strings, and fails on all other input.

**Returns:** [Decoder](_decoder_.decoder.md)<`string`>

___
<a id="succeed"></a>

### `<Static>` succeed

▸ **succeed**A(fixedValue: *`A`*): [Decoder](_decoder_.decoder.md)<`A`>

Decoder that ignores the input json and always succeeds with `fixedValue`.

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| fixedValue | `A` |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="tuple"></a>

### `<Static>` tuple

▸ **tuple**A(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>]*): [Decoder](_decoder_.decoder.md)<[`A`]>

▸ **tuple**A,B(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`]>

▸ **tuple**A,B,C(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`]>

▸ **tuple**A,B,C,D(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`]>

▸ **tuple**A,B,C,D,E(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`]>

▸ **tuple**A,B,C,D,E,F(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`, `F`]>

▸ **tuple**A,B,C,D,E,F,G(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>, [Decoder](_decoder_.decoder.md)<`G`>]*): [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`, `F`, `G`]>

▸ **tuple**A,B,C,D,E,F,G,H(decoder: *[[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>, [Decoder](_decoder_.decoder.md)<`G`>, [Decoder](_decoder_.decoder.md)<`H`>]*): [Decoder](_decoder_.decoder.md)<[`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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`]>

**Type parameters:**

#### A 
#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`]>

**Type parameters:**

#### A 
#### B 
#### C 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`]>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`]>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`]>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`, `F`]>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>, [Decoder](_decoder_.decoder.md)<`G`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`, `F`, `G`]>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
#### H 
**Parameters:**

| Param | Type |
| ------ | ------ |
| decoder | [[Decoder](_decoder_.decoder.md)<`A`>, [Decoder](_decoder_.decoder.md)<`B`>, [Decoder](_decoder_.decoder.md)<`C`>, [Decoder](_decoder_.decoder.md)<`D`>, [Decoder](_decoder_.decoder.md)<`E`>, [Decoder](_decoder_.decoder.md)<`F`>, [Decoder](_decoder_.decoder.md)<`G`>, [Decoder](_decoder_.decoder.md)<`H`>] |

**Returns:** [Decoder](_decoder_.decoder.md)<[`A`, `B`, `C`, `D`, `E`, `F`, `G`, `H`]>

___
<a id="union"></a>

### `<Static>` union

▸ **union**A,B(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B`>

▸ **union**A,B,C(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C`>

▸ **union**A,B,C,D(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D`>

▸ **union**A,B,C,D,E(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E`>

▸ **union**A,B,C,D,E,F(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F`>

▸ **union**A,B,C,D,E,F,G(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*, gd: *[Decoder](_decoder_.decoder.md)<`G`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F` &#124; `G`>

▸ **union**A,B,C,D,E,F,G,H(ad: *[Decoder](_decoder_.decoder.md)<`A`>*, bd: *[Decoder](_decoder_.decoder.md)<`B`>*, cd: *[Decoder](_decoder_.decoder.md)<`C`>*, dd: *[Decoder](_decoder_.decoder.md)<`D`>*, ed: *[Decoder](_decoder_.decoder.md)<`E`>*, fd: *[Decoder](_decoder_.decoder.md)<`F`>*, gd: *[Decoder](_decoder_.decoder.md)<`G`>*, hd: *[Decoder](_decoder_.decoder.md)<`H`>*): [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F` &#124; `G` &#124; `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:**

#### A 
#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B`>

**Type parameters:**

#### A 
#### B 
#### C 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |
| gd | [Decoder](_decoder_.decoder.md)<`G`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F` &#124; `G`>

**Type parameters:**

#### A 
#### B 
#### C 
#### D 
#### E 
#### F 
#### G 
#### H 
**Parameters:**

| Param | Type |
| ------ | ------ |
| ad | [Decoder](_decoder_.decoder.md)<`A`> |
| bd | [Decoder](_decoder_.decoder.md)<`B`> |
| cd | [Decoder](_decoder_.decoder.md)<`C`> |
| dd | [Decoder](_decoder_.decoder.md)<`D`> |
| ed | [Decoder](_decoder_.decoder.md)<`E`> |
| fd | [Decoder](_decoder_.decoder.md)<`F`> |
| gd | [Decoder](_decoder_.decoder.md)<`G`> |
| hd | [Decoder](_decoder_.decoder.md)<`H`> |

**Returns:** [Decoder](_decoder_.decoder.md)< `A` &#124; `B` &#124; `C` &#124; `D` &#124; `E` &#124; `F` &#124; `G` &#124; `H`>

___
<a id="unknownjson"></a>

### `<Static>` unknownJson

▸ **unknownJson**(): [Decoder](_decoder_.decoder.md)<`unknown`>

Decoder identity function which always succeeds and types the result as `unknown`.

**Returns:** [Decoder](_decoder_.decoder.md)<`unknown`>

___
<a id="valueat"></a>

### `<Static>` valueAt

▸ **valueAt**A(paths: *( `string` &#124; `number`)[]*, decoder: *[Decoder](_decoder_.decoder.md)<`A`>*): [Decoder](_decoder_.decoder.md)<`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:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| paths | ( `string` &#124; `number`)[] |
| decoder | [Decoder](_decoder_.decoder.md)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___
<a id="withdefault"></a>

### `<Static>` withDefault

▸ **withDefault**A(defaultValue: *`A`*, decoder: *[Decoder](_decoder_.decoder.md)<`A`>*): [Decoder](_decoder_.decoder.md)<`A`>

Decoder that always succeeds with either the decoded value, or a fallback default value.

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| defaultValue | `A` |
| decoder | [Decoder](_decoder_.decoder.md)<`A`> |

**Returns:** [Decoder](_decoder_.decoder.md)<`A`>

___



================================================
FILE: docs/interfaces/_decoder_.decodererror.md
================================================
[@mojotech/json-type-validation](../README.md) > ["decoder"](../modules/_decoder_.md) > [DecoderError](../interfaces/_decoder_.decodererror.md)

# Interface: DecoderError

Information describing how json data failed to match a decoder. Includes the full input json, since in most cases it's useless to know how a decoder failed without also seeing the malformed data.

## Hierarchy

**DecoderError**

## Index

### Properties

* [at](_decoder_.decodererror.md#at)
* [input](_decoder_.decodererror.md#input)
* [kind](_decoder_.decodererror.md#kind)
* [message](_decoder_.decodererror.md#message)

---

## Properties

<a id="at"></a>

###  at

**● at**: *`string`*

___
<a id="input"></a>

###  input

**● input**: *`unknown`*

___
<a id="kind"></a>

###  kind

**● kind**: *"DecoderError"*

___
<a id="message"></a>

###  message

**● message**: *`string`*

___



================================================
FILE: docs/interfaces/_result_.err.md
================================================
[@mojotech/json-type-validation](../README.md) > ["result"](../modules/_result_.md) > [Err](../interfaces/_result_.err.md)

# Interface: Err

The error type variant for `Result`. Denotes that some error occurred before the result was computed.

## Type parameters
#### E 
## Hierarchy

**Err**

## Index

### Properties

* [error](_result_.err.md#error)
* [ok](_result_.err.md#ok)

---

## Properties

<a id="error"></a>

###  error

**● error**: *`E`*

___
<a id="ok"></a>

###  ok

**● ok**: *`false`*

___



================================================
FILE: docs/interfaces/_result_.ok.md
================================================
[@mojotech/json-type-validation](../README.md) > ["result"](../modules/_result_.md) > [Ok](../interfaces/_result_.ok.md)

# Interface: Ok

The success type variant for `Result`. Denotes that a result value was computed with no errors.

## Type parameters
#### V 
## Hierarchy

**Ok**

## Index

### Properties

* [ok](_result_.ok.md#ok)
* [result](_result_.ok.md#result)

---

## Properties

<a id="ok"></a>

###  ok

**● ok**: *`true`*

___
<a id="result"></a>

###  result

**● result**: *`V`*

___



================================================
FILE: docs/modules/_combinators_.md
================================================
[@mojotech/json-type-validation](../README.md) > ["combinators"](../modules/_combinators_.md)

# External module: "combinators"

## Index

### Variables

* [anyJson](_combinators_.md#anyjson)
* [array](_combinators_.md#array)
* [boolean](_combinators_.md#boolean)
* [constant](_combinators_.md#constant)
* [dict](_combinators_.md#dict)
* [fail](_combinators_.md#fail)
* [intersection](_combinators_.md#intersection)
* [lazy](_combinators_.md#lazy)
* [number](_combinators_.md#number)
* [object](_combinators_.md#object)
* [oneOf](_combinators_.md#oneof)
* [optional](_combinators_.md#optional)
* [string](_combinators_.md#string)
* [succeed](_combinators_.md#succeed)
* [tuple](_combinators_.md#tuple)
* [union](_combinators_.md#union)
* [unknownJson](_combinators_.md#unknownjson)
* [valueAt](_combinators_.md#valueat)
* [withDefault](_combinators_.md#withdefault)

---

## Variables

<a id="anyjson"></a>

### `<Const>` anyJson

**● anyJson**: *[anyJson]()* =  Decoder.anyJson

See `Decoder.anyJson`

___
<a id="array"></a>

### `<Const>` array

**● array**: *[array](../classes/_decoder_.decoder.md#array)* =  Decoder.array

See `Decoder.array`

___
<a id="boolean"></a>

### `<Const>` boolean

**● boolean**: *[boolean](../classes/_decoder_.decoder.md#boolean)* =  Decoder.boolean

See `Decoder.boolean`

___
<a id="constant"></a>

### `<Const>` constant

**● constant**: *[constant](../classes/_decoder_.decoder.md#constant)* =  Decoder.constant

See `Decoder.constant`

___
<a id="dict"></a>

### `<Const>` dict

**● dict**: *[dict]()* =  Decoder.dict

See `Decoder.dict`

___
<a id="fail"></a>

### `<Const>` fail

**● fail**: *[fail]()* =  Decoder.fail

See `Decoder.fail`

___
<a id="intersection"></a>

### `<Const>` intersection

**● intersection**: *[intersection](../classes/_decoder_.decoder.md#intersection)* =  Decoder.intersection

See `Decoder.intersection`

___
<a id="lazy"></a>

### `<Const>` lazy

**● lazy**: *[lazy]()* =  Decoder.lazy

See `Decoder.lazy`

___
<a id="number"></a>

### `<Const>` number

**● number**: *[number](../classes/_decoder_.decoder.md#number)* =  Decoder.number

See `Decoder.number`

___
<a id="object"></a>

### `<Const>` object

**● object**: *[object](../classes/_decoder_.decoder.md#object)* =  Decoder.object

See `Decoder.object`

___
<a id="oneof"></a>

### `<Const>` oneOf

**● oneOf**: *[oneOf]()* =  Decoder.oneOf

See `Decoder.oneOf`

___
<a id="optional"></a>

### `<Const>` optional

**● optional**: *[optional]()* =  Decoder.optional

See `Decoder.optional`

___
<a id="string"></a>

### `<Const>` string

**● string**: *[string](../classes/_decoder_.decoder.md#string)* =  Decoder.string

See `Decoder.string`

___
<a id="succeed"></a>

### `<Const>` succeed

**● succeed**: *[succeed]()* =  Decoder.succeed

See `Decoder.succeed`

___
<a id="tuple"></a>

### `<Const>` tuple

**● tuple**: *[tuple](../classes/_decoder_.decoder.md#tuple)* =  Decoder.tuple

See `Decoder.tuple`

___
<a id="union"></a>

### `<Const>` union

**● union**: *[union](../classes/_decoder_.decoder.md#union)* =  Decoder.union

See `Decoder.union`

___
<a id="unknownjson"></a>

### `<Const>` unknownJson

**● unknownJson**: *`function`* =  Decoder.unknownJson

See `Decoder.unknownJson`

#### Type declaration
▸(): [Decoder](../classes/_decoder_.decoder.md)<`unknown`>

**Returns:** [Decoder](../classes/_decoder_.decoder.md)<`unknown`>

___
<a id="valueat"></a>

### `<Const>` valueAt

**● valueAt**: *[valueAt]()* =  Decoder.valueAt

See `Decoder.valueAt`

___
<a id="withdefault"></a>

### `<Const>` withDefault

**● withDefault**: *[withDefault]()* =  Decoder.withDefault

See `Decoder.withDefault`

___



================================================
FILE: docs/modules/_decoder_.md
================================================
[@mojotech/json-type-validation](../README.md) > ["decoder"](../modules/_decoder_.md)

# External module: "decoder"

## Index

### Classes

* [Decoder](../classes/_decoder_.decoder.md)

### Interfaces

* [DecoderError](../interfaces/_decoder_.decodererror.md)

### Type aliases

* [DecoderObject](_decoder_.md#decoderobject)

### Functions

* [isDecoderError](_decoder_.md#isdecodererror)

---

## Type aliases

<a id="decoderobject"></a>

###  DecoderObject

**ΤDecoderObject**: *`object`*

Defines a mapped type over an interface `A`. `DecoderObject<A>` is an interface that has all the keys or `A`, but each key's property type is mapped to a decoder for that type. This type is used when creating decoders for objects.

Example:

```
interface X {
  a: boolean;
  b: string;
}

const decoderObject: DecoderObject<X> = {
  a: boolean(),
  b: string()
}
```

#### Type declaration

___

## Functions

<a id="isdecodererror"></a>

### `<Const>` isDecoderError

▸ **isDecoderError**(a: *`any`*): `boolean`

Type guard for `DecoderError`. One use case of the type guard is in the `catch` of a promise. Typescript types the error argument of `catch` as `any`, so when dealing with a decoder as a promise you may need to distinguish between a `DecoderError` and an error string.

**Parameters:**

| Param | Type |
| ------ | ------ |
| a | `any` |

**Returns:** `boolean`

___



================================================
FILE: docs/modules/_index_.md
================================================
[@mojotech/json-type-validation](../README.md) > ["index"](../modules/_index_.md)

# External module: "index"

## Index

---



================================================
FILE: docs/modules/_result_.md
================================================
[@mojotech/json-type-validation](../README.md) > ["result"](../modules/_result_.md)

# External module: "result"

## Index

### Interfaces

* [Err](../interfaces/_result_.err.md)
* [Ok](../interfaces/_result_.ok.md)

### Type aliases

* [Result](_result_.md#result)

### Functions

* [andThen](_result_.md#andthen)
* [asPromise](_result_.md#aspromise)
* [err](_result_.md#err-1)
* [isErr](_result_.md#iserr)
* [isOk](_result_.md#isok)
* [map](_result_.md#map)
* [map2](_result_.md#map2)
* [mapError](_result_.md#maperror)
* [ok](_result_.md#ok-1)
* [successes](_result_.md#successes)
* [withDefault](_result_.md#withdefault)
* [withException](_result_.md#withexception)

---

## Type aliases

<a id="result"></a>

###  Result

**ΤResult**: * [Ok](../interfaces/_result_.ok.md)<`V`> &#124; [Err](../interfaces/_result_.err.md)<`E`>
*

The result of a computation that may fail. The decoding function `Decoder.run` returns a `Result`. The value of a `Result` is either `Ok` if the computation succeeded, or `Err` if there was some failure in the process.

___

## Functions

<a id="andthen"></a>

### `<Const>` andThen

▸ **andThen**A,B,E(f: *`function`*, r: *[Result](_result_.md#result)<`A`, `E`>*): [Result](_result_.md#result)<`B`, `E`>

Chain together a sequence of computations that may fail, similar to a `Promise`. If the first computation fails then the error will propagate through. If it succeeds, then `f` will be applied to the value, returning a new `Result`.

**Type parameters:**

#### A 
#### B 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |
| r | [Result](_result_.md#result)<`A`, `E`> |

**Returns:** [Result](_result_.md#result)<`B`, `E`>

___
<a id="aspromise"></a>

### `<Const>` asPromise

▸ **asPromise**V(r: *[Result](_result_.md#result)<`V`, `any`>*): `Promise`<`V`>

Create a `Promise` that either resolves with the result of `Ok` or rejects with the error of `Err`.

**Type parameters:**

#### V 
**Parameters:**

| Param | Type |
| ------ | ------ |
| r | [Result](_result_.md#result)<`V`, `any`> |

**Returns:** `Promise`<`V`>

___
<a id="err-1"></a>

### `<Const>` err

▸ **err**E(error: *`E`*): [Err](../interfaces/_result_.err.md)<`E`>

Wraps errors in an `Err` type.

Example: `err('on fire') // => {ok: false, error: 'on fire'}`

**Type parameters:**

#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| error | `E` |

**Returns:** [Err](../interfaces/_result_.err.md)<`E`>

___
<a id="iserr"></a>

### `<Const>` isErr

▸ **isErr**E(r: *[Result](_result_.md#result)<`any`, `E`>*): `boolean`

Typeguard for `Err`.

**Type parameters:**

#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| r | [Result](_result_.md#result)<`any`, `E`> |

**Returns:** `boolean`

___
<a id="isok"></a>

### `<Const>` isOk

▸ **isOk**V(r: *[Result](_result_.md#result)<`V`, `any`>*): `boolean`

Typeguard for `Ok`.

**Type parameters:**

#### V 
**Parameters:**

| Param | Type |
| ------ | ------ |
| r | [Result](_result_.md#result)<`V`, `any`> |

**Returns:** `boolean`

___
<a id="map"></a>

### `<Const>` map

▸ **map**A,B,E(f: *`function`*, r: *[Result](_result_.md#result)<`A`, `E`>*): [Result](_result_.md#result)<`B`, `E`>

Apply `f` to the result of an `Ok`, or pass the error through.

**Type parameters:**

#### A 
#### B 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |
| r | [Result](_result_.md#result)<`A`, `E`> |

**Returns:** [Result](_result_.md#result)<`B`, `E`>

___
<a id="map2"></a>

### `<Const>` map2

▸ **map2**A,B,C,E(f: *`function`*, ar: *[Result](_result_.md#result)<`A`, `E`>*, br: *[Result](_result_.md#result)<`B`, `E`>*): [Result](_result_.md#result)<`C`, `E`>

Apply `f` to the result of two `Ok`s, or pass an error through. If both `Result`s are errors then the first one is returned.

**Type parameters:**

#### A 
#### B 
#### C 
#### E 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |
| ar | [Result](_result_.md#result)<`A`, `E`> |
| br | [Result](_result_.md#result)<`B`, `E`> |

**Returns:** [Result](_result_.md#result)<`C`, `E`>

___
<a id="maperror"></a>

### `<Const>` mapError

▸ **mapError**V,A,B(f: *`function`*, r: *[Result](_result_.md#result)<`V`, `A`>*): [Result](_result_.md#result)<`V`, `B`>

Apply `f` to the error of an `Err`, or pass the success through.

**Type parameters:**

#### V 
#### A 
#### B 
**Parameters:**

| Param | Type |
| ------ | ------ |
| f | `function` |
| r | [Result](_result_.md#result)<`V`, `A`> |

**Returns:** [Result](_result_.md#result)<`V`, `B`>

___
<a id="ok-1"></a>

### `<Const>` ok

▸ **ok**V(result: *`V`*): [Ok](../interfaces/_result_.ok.md)<`V`>

Wraps values in an `Ok` type.

Example: `ok(5) // => {ok: true, result: 5}`

**Type parameters:**

#### V 
**Parameters:**

| Param | Type |
| ------ | ------ |
| result | `V` |

**Returns:** [Ok](../interfaces/_result_.ok.md)<`V`>

___
<a id="successes"></a>

### `<Const>` successes

▸ **successes**A(results: *[Result](_result_.md#result)<`A`, `any`>[]*): `A`[]

Given an array of `Result`s, return the successful values.

**Type parameters:**

#### A 
**Parameters:**

| Param | Type |
| ------ | ------ |
| results | [Result](_result_.md#result)<`A`, `any`>[] |

**Returns:** `A`[]

___
<a id="withdefault"></a>

### `<Const>` withDefault

▸ **withDefault**V(defaultValue: *`V`*, r: *[Result](_result_.md#result)<`V`, `any`>*): `V`

Unwraps a `Result` and returns either the result of an `Ok`, or `defaultValue`.

Example:

```
Result.withDefault(5, number().run(json))
```

It would be nice if `Decoder` had an instance method that mirrored this function. Such a method would look something like this:

```
class Decoder<A> {
  runWithDefault = (defaultValue: A, json: any): A =>
    Result.withDefault(defaultValue, this.run(json));
}

number().runWithDefault(5, json)
```

Unfortunately, the type of `defaultValue: A` on the method causes issues with type inference on the `object` decoder in some situations. While these inference issues can be solved by providing the optional type argument for `object`s, the extra trouble and confusion doesn't seem worth it.

**Type parameters:**

#### V 
**Parameters:**

| Param | Type |
| ------ | ------ |
| defaultValue | `V` |
| r | [Result](_result_.md#result)<`V`, `any`> |

**Returns:** `V`

___
<a id="withexception"></a>

### `<Const>` withException

▸ **withException**V(r: *[Result](_result_.md#result)<`V`, `any`>*): `V`

Return the successful result, or throw an error.

**Type parameters:**

#### V 
**Parameters:**

| Param | Type |
| ------ | ------ |
| r | [Result](_result_.md#result)<`V`, `any`> |

**Returns:** `V`

___



================================================
FILE: nix-files/default.nix
================================================
{ nixpkgsFn ? import ./nixpkgs.nix
, system ? null }:
let nixpkgs = nixpkgsFn ({
      # extra config goes here
    } // ( if system == null then {} else { inherit system; } ));
in
nixpkgs.stdenv.mkDerivation {
  name = "json-type-validator";
  buildInputs = with nixpkgs; [ nodejs yarn git ];
  src = "./";

  builder = builtins.toFile "builder.sh" ''
    echo "Use this derivation with nix-shell only"

    exit 1
  '';

  shellHook = ''
    # Get to the source directory
    cd $src
    # Install any new dependencies
    yarn
    # Add node_modules to path
    export PATH=$src/node_modules/bin:$PATH
  '';
}


================================================
FILE: nix-files/nixpkgs.nix
================================================
let source = ''
      {
        "owner": "NixOS",
        "repo": "nixpkgs-channels",
        "rev": "aebdc892d6aa6834a083fb8b56c43578712b0dab",
        "sha256": "1bcpjc7f1ff5k7vf5rwwb7g7m4j238hi4ssnx7xqglr7hj4ms0cz"
      }
      '';
in
import ((import <nixpkgs> {}).fetchFromGitHub (builtins.fromJSON (source)))


================================================
FILE: nix-files/shell.nix
================================================
{ nixpkgsFn ? import ./nixpkgs.nix
, package ? ./default.nix
}:
(import package { inherit nixpkgsFn; })


================================================
FILE: package.json
================================================
{
  "name": "@mojotech/json-type-validation",
  "version": "3.1.0",
  "description": "runtime type checking and validation of untyped JSON data",
  "keywords": [
    "TypeScript",
    "JSON"
  ],
  "main": "dist/index.js",
  "module": "dist/index.es5.js",
  "typings": "dist/types/index.d.ts",
  "files": [
    "dist"
  ],
  "author": "Elias Mulhall <elias@mojotech.com>",
  "repository": {
    "type": "git",
    "url": "https://github.com/mojotech/json-type-validation"
  },
  "bugs": {
    "url": "https://github.com/mojotech/json-type-validation/issues"
  },
  "homepage": "https://github.com/mojotech/json-type-validation",
  "license": "MIT",
  "engines": {
    "node": ">=6.0.0"
  },
  "scripts": {
    "lint": "tslint -t codeFrame --project tsconfig-test.json",
    "prebuild": "rimraf dist",
    "build": "tsc --module commonjs --outDir dist/lib && rollup -c rollup.config.ts && typedoc --out docs --target es6 --theme markdown --readme DOCS.md --mdHideSources --mode modules --excludeNotExported src",
    "start": "rollup -c rollup.config.ts -w",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:prod": "npm run lint && npm run test -- --coverage --no-cache",
    "typecheck": "tsc --lib es2015 --noEmit --strict test/**.ts",
    "typecheck:watch": "tsc -w --lib es2015 --noEmit --strict test/**.ts"
  },
  "jest": {
    "transform": {
      ".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
    },
    "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js"
    ],
    "coveragePathIgnorePatterns": [
      "/node_modules/",
      "/test/"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 90,
        "functions": 95,
        "lines": 95,
        "statements": 95
      }
    },
    "collectCoverage": true
  },
  "devDependencies": {
    "@types/jest": "^22.2.3",
    "@types/node": "^10.5.3",
    "@types/lodash": "^4.5.0",
    "colors": "^1.1.2",
    "cross-env": "^5.0.1",
    "jest": "^22.0.2",
    "prettier": "^1.4.4",
    "rimraf": "^2.6.1",
    "rollup": "^0.53.0",
    "rollup-plugin-commonjs": "^8.0.2",
    "rollup-plugin-node-resolve": "^3.0.0",
    "rollup-plugin-sourcemaps": "^0.4.2",
    "rollup-plugin-typescript2": "^0.9.0",
    "ts-jest": "^22.0.0",
    "ts-node": "^4.1.0",
    "tslint": "^5.11.0",
    "tslint-config-prettier": "^1.14.0",
    "tslint-config-standard": "^7.1.0",
    "typedoc": "^0.13.0",
    "typedoc-plugin-markdown": "^1.0.13",
    "typescript": "~3.1.0"
  },
  "dependencies": {
    "lodash": "^4.5.0"
  }
}


================================================
FILE: rollup.config.ts
================================================
import resolve from 'rollup-plugin-node-resolve';
import sourceMaps from 'rollup-plugin-sourcemaps';
import typescript from 'rollup-plugin-typescript2';

const pkg = require('./package.json');

export default {
  input: `src/index.ts`,
  output: [
    {
      file: pkg.main,
      name: 'index',
      format: 'cjs',
      sourcemap: true
    },
    {
      file: pkg.module,
      format: 'es',
      sourcemap: true
    }
  ],
  external: id => {
    return id.includes('/node_modules/');
  },
  watch: {
    include: 'src/**'
  },
  plugins: [
    // Compile TypeScript files
    typescript({
      useTsconfigDeclarationDir: true
    }),
    resolve(),

    // Resolve source maps to the original source
    sourceMaps()
  ]
};


================================================
FILE: src/combinators.ts
================================================
import {Decoder} from './decoder';

/* tslint:disable:variable-name */

/** See `Decoder.string` */
export const string = Decoder.string;

/** See `Decoder.number` */
export const number = Decoder.number;

/** See `Decoder.boolean` */
export const boolean = Decoder.boolean;

/** See `Decoder.anyJson` */
export const anyJson = Decoder.anyJson;

/** See `Decoder.unknownJson` */
export const unknownJson: () => Decoder<unknown> = Decoder.unknownJson;

/** See `Decoder.constant` */
export const constant = Decoder.constant;

/** See `Decoder.object` */
export const object = Decoder.object;

/** See `Decoder.array` */
export const array = Decoder.array;

/** See `Decoder.tuple` */
export const tuple = Decoder.tuple;

/** See `Decoder.dict` */
export const dict = Decoder.dict;

/** See `Decoder.optional` */
export const optional = Decoder.optional;

/** See `Decoder.oneOf` */
export const oneOf = Decoder.oneOf;

/** See `Decoder.union` */
export const union = Decoder.union;

/** See `Decoder.intersection` */
export const intersection = Decoder.intersection;

/** See `Decoder.withDefault` */
export const withDefault = Decoder.withDefault;

/** See `Decoder.valueAt` */
export const valueAt = Decoder.valueAt;

/** See `Decoder.succeed` */
export const succeed = Decoder.succeed;

/** See `Decoder.fail` */
export const fail = Decoder.fail;

/** See `Decoder.lazy` */
export const lazy = Decoder.lazy;


================================================
FILE: src/decoder.ts
================================================
import * as Result from './result';
import isEqual from "lodash/isEqual"

/**
 * Information describing how json data failed to match a decoder.
 * Includes the full input json, since in most cases it's useless to know how a
 * decoder failed without also seeing the malformed data.
 */
export interface DecoderError {
  kind: 'DecoderError';
  input: unknown;
  at: string;
  message: string;
}

/**
 * Alias for the result of the `Decoder.run` method. On success returns `Ok`
 * with the decoded value of type `A`, on failure returns `Err` containing a
 * `DecoderError`.
 */
type RunResult<A> = Result.Result<A, DecoderError>;

/**
 * Alias for the result of the internal `Decoder.decode` method. Since `decode`
 * is a private function it returns a partial decoder error on failure, which
 * will be completed and polished when handed off to the `run` method.
 */
type DecodeResult<A> = Result.Result<A, Partial<DecoderError>>;

/**
 * Defines a mapped type over an interface `A`. `DecoderObject<A>` is an
 * interface that has all the keys or `A`, but each key's property type is
 * mapped to a decoder for that type. This type is used when creating decoders
 * for objects.
 *
 * Example:
 * ```
 * interface X {
 *   a: boolean;
 *   b: string;
 * }
 *
 * const decoderObject: DecoderObject<X> = {
 *   a: boolean(),
 *   b: string()
 * }
 * ```
 */
export type DecoderObject<A> = {[t in keyof A]: Decoder<A[t]>};

/**
 * Type guard for `DecoderError`. One use case of the type guard is in the
 * `catch` of a promise. Typescript types the error argument of `catch` as
 * `any`, so when dealing with a decoder as a promise you may need to
 * distinguish between a `DecoderError` and an error string.
 */
export const isDecoderError = (a: any): a is DecoderError =>
  a.kind === 'DecoderError' && typeof a.at === 'string' && typeof a.message === 'string';

/*
 * Helpers
 */
const isJsonArray = (json: any): json is unknown[] => Array.isArray(json);

const isJsonObject = (json: any): json is Record<string, unknown> =>
  typeof json === 'object' && json !== null && !isJsonArray(json);

const typeString = (json: unknown): string => {
  switch (typeof json) {
    case 'string':
      return 'a string';
    case 'number':
      return 'a number';
    case 'boolean':
      return 'a boolean';
    case 'undefined':
      return 'undefined';
    case 'object':
      if (json instanceof Array) {
        return 'an array';
      } else if (json === null) {
        return 'null';
      } else {
        return 'an object';
      }
    default:
      return JSON.stringify(json);
  }
};

const expectedGot = (expected: string, got: unknown) =>
  `expected ${expected}, got ${typeString(got)}`;

const printPath = (paths: (string | number)[]): string =>
  paths.map(path => (typeof path === 'string' ? `.${path}` : `[${path}]`)).join('');

const prependAt = (newAt: string, {at, ...rest}: Partial<DecoderError>): Partial<DecoderError> => ({
  at: newAt + (at || ''),
  ...rest
});

/**
 * 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.
 */
export class Decoder<A> {
  /**
   * 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.
   */
  private constructor(private decode: (json: unknown) => DecodeResult<A>) {}

  /**
   * Decoder primitive that validates strings, and fails on all other input.
   */
  static string(): Decoder<string> {
    return new Decoder<string>(
      (json: unknown) =>
        typeof json === 'string'
          ? Result.ok(json)
          : Result.err({message: expectedGot('a string', json)})
    );
  }

  /**
   * Decoder primitive that validates numbers, and fails on all other input.
   */
  static number(): Decoder<number> {
    return new Decoder<number>(
      (json: unknown) =>
        typeof json === 'number'
          ? Result.ok(json)
          : Result.err({message: expectedGot('a number', json)})
    );
  }

  /**
   * Decoder primitive that validates booleans, and fails on all other input.
   */
  static boolean(): Decoder<boolean> {
    return new Decoder<boolean>(
      (json: unknown) =>
        typeof json === 'boolean'
          ? Result.ok(json)
          : Result.err({message: expectedGot('a boolean', json)})
    );
  }

  /**
   * 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()
   * });
   * ```
   */
  static anyJson = (): Decoder<any> => new Decoder<any>((json: any) => Result.ok(json));

  /**
   * Decoder identity function which always succeeds and types the result as
   * `unknown`.
   */
  static unknownJson = (): Decoder<unknown> =>
    new Decoder<unknown>((json: unknown) => Result.ok(json));

  /**
   * Decoder primitive that only matches on exact values.
   *
   * For primitive values and shallow structures of primitive values `constant`
   * will infer an exact literal type:
   * ```
   *  | Decoder                      | Type                          |
   *  | ---------------------------- | ------------------------------|
   *  | constant(true)               | Decoder<true>                 |
   *  | constant(false)              | Decoder<false>                |
   *  | constant(null)               | Decoder<null>                 |
   *  | constant(undefined)          | Decoder<undefined>            |
   *  | constant('alaska')           | Decoder<'alaska'>             |
   *  | constant(50)                 | Decoder<50>                   |
   *  | constant([1,2,3])            | Decoder<[1,2,3]>              |
   *  | constant({x: 't'})           | Decoder<{x: 't'}>             |
   * ```
   *
   * Inference breaks on nested structures, which require an annotation to get
   * the literal type:
   * ```
   *  | Decoder                      | Type                          |
   *  | -----------------------------|-------------------------------|
   *  | constant([1,[2]])            | Decoder<(number|number[])[]>  |
   *  | constant<[1,[2]]>([1,[2]])   | Decoder<[1,[2]]>              |
   *  | constant({x: [1]})           | Decoder<{x: number[]}>        |
   *  | constant<{x: [1]}>({x: [1]}) | Decoder<{x: [1]}>             |
   * ```
   */
  static constant<T extends string | number | boolean | []>(value: T): Decoder<T>;
  static constant<T extends string | number | boolean, U extends [T, ...T[]]>(value: U): Decoder<U>;
  static constant<T extends string | number | boolean, U extends Record<string, T>>(value: U): Decoder<U>;
  static constant<T>(value: T): Decoder<T>;
  static constant(value: any) {
    return new Decoder(
      (json: unknown) =>
        isEqual(json, value)
          ? Result.ok(value)
          : Result.err({message: `expected ${JSON.stringify(value)}, got ${JSON.stringify(json)}`})
    );
  }

  /**
   * 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']}
   * ```
   */
  static object(): Decoder<Record<string, unknown>>;
  static object<A>(decoders: DecoderObject<A>): Decoder<A>;
  static object<A>(decoders?: DecoderObject<A>) {
    return new Decoder((json: unknown) => {
      if (isJsonObject(json) && decoders) {
        let obj: any = {};
        for (const key in decoders) {
          if (decoders.hasOwnProperty(key)) {
            const r = decoders[key].decode(json[key]);
            if (r.ok === true) {
              // tslint:disable-next-line:strict-type-predicates
              if (r.result !== undefined) {
                obj[key] = r.result;
              }
            } else if (json[key] === undefined) {
              return Result.err({message: `the key '${key}' is required but was not present`});
            } else {
              return Result.err(prependAt(`.${key}`, r.error));
            }
          }
        }
        return Result.ok(obj);
      } else if (isJsonObject(json)) {
        return Result.ok(json);
      } else {
        return Result.err({message: expectedGot('an object', json)});
      }
    });
  }

  /**
   * 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"}}
   * ```
   */
  static array(): Decoder<unknown[]>;
  static array<A>(decoder: Decoder<A>): Decoder<A[]>;
  static array<A>(decoder?: Decoder<A>) {
    return new Decoder(json => {
      if (isJsonArray(json) && decoder) {
        const decodeValue = (v: unknown, i: number): DecodeResult<A> =>
          Result.mapError(err => prependAt(`[${i}]`, err), decoder.decode(v));

        return json.reduce(
          (acc: DecodeResult<A[]>, v: unknown, i: number) =>
            Result.map2((arr, result) => [...arr, result], acc, decodeValue(v, i)),
          Result.ok([])
        );
      } else if (isJsonArray(json)) {
        return Result.ok(json);
      } else {
        return Result.err({message: expectedGot('an array', json)});
      }
    });
  }

  /**
   * 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']}
   * ```
   */
  static tuple<A>(decoder: [Decoder<A>]): Decoder<[A]>;
  static tuple<A, B>(decoder: [Decoder<A>, Decoder<B>]): Decoder<[A, B]>;
  static tuple<A, B, C>(decoder: [Decoder<A>, Decoder<B>, Decoder<C>]): Decoder<[A, B, C]>;
  static tuple<A, B, C, D>(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>]): Decoder<[A, B, C, D]>; // prettier-ignore
  static tuple<A, B, C, D, E>(decoder: [Decoder<A>, Decoder<B>, Decoder<C>, Decoder<D>, Decoder<E>]): Decoder<[A, B, C, D, E]>; // prettier-ignore
  static tuple<A, 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]>; // prettier-ignore
  static tuple<A, 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]>; // prettier-ignore
  static tuple<A, 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]>; // prettier-ignore
  static tuple<A>(decoders: Decoder<A>[]) {
    return new Decoder((json: unknown) => {
      if (isJsonArray(json)) {
        if (json.length !== decoders.length) {
          return Result.err({
            message: `expected a tuple of length ${decoders.length}, got one of length ${
              json.length
            }`
          });
        }
        const result = [];
        for (let i: number = 0; i < decoders.length; i++) {
          const nth = decoders[i].decode(json[i]);
          if (nth.ok) {
            result[i] = nth.result;
          } else {
            return Result.err(prependAt(`[${i}]`, nth.error));
          }
        }
        return Result.ok(result);
      } else {
        return Result.err({message: expectedGot(`a tuple of length ${decoders.length}`, json)});
      }
    });
  }

  /**
   * 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}}
   * ```
   */
  static dict = <A>(decoder: Decoder<A>): Decoder<Record<string, A>> =>
    new Decoder(json => {
      if (isJsonObject(json)) {
        let obj: Record<string, A> = {};
        for (const key in json) {
          if (json.hasOwnProperty(key)) {
            const r = decoder.decode(json[key]);
            if (r.ok === true) {
              obj[key] = r.result;
            } else {
              return Result.err(prependAt(`.${key}`, r.error));
            }
          }
        }
        return Result.ok(obj);
      } else {
        return Result.err({message: expectedGot('an object', json)});
      }
    });

  /**
   * 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())
   * });
   * ```
   */
  static optional = <A>(decoder: Decoder<A>): Decoder<undefined | A> =>
    new Decoder<undefined | A>(
      (json: unknown) => (json === undefined ? Result.ok(undefined) : decoder.decode(json))
    );

  /**
   * 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'))
   * ```
   */
  static oneOf = <A>(...decoders: Decoder<A>[]): Decoder<A> =>
    new Decoder<A>((json: unknown) => {
      const errors: Partial<DecoderError>[] = [];
      for (let i: number = 0; i < decoders.length; i++) {
        const r = decoders[i].decode(json);
        if (r.ok === true) {
          return r;
        } else {
          errors[i] = r.error;
        }
      }
      const errorsList = errors
        .map(error => `at error${error.at || ''}: ${error.message}`)
        .join('", "');
      return Result.err({
        message: `expected a value matching one of the decoders, got the errors ["${errorsList}"]`
      });
    });

  /**
   * 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()}));
   * ```
   */
  static union <A, B>(ad: Decoder<A>, bd: Decoder<B>): Decoder<A | B>; // prettier-ignore
  static union <A, B, C>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder<A | B | C>; // prettier-ignore
  static union <A, B, C, D>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder<A | B | C | D>; // prettier-ignore
  static 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>; // prettier-ignore
  static 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>; // prettier-ignore
  static 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>; // prettier-ignore
  static 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>; // prettier-ignore
  static union(ad: Decoder<any>, bd: Decoder<any>, ...decoders: Decoder<any>[]): Decoder<any> {
    return Decoder.oneOf(ad, bd, ...decoders);
  }

  /**
   * 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()}));
   * ```
   */
  static intersection <A, B>(ad: Decoder<A>, bd: Decoder<B>): Decoder<A & B>; // prettier-ignore
  static intersection <A, B, C>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>): Decoder<A & B & C>; // prettier-ignore
  static intersection <A, B, C, D>(ad: Decoder<A>, bd: Decoder<B>, cd: Decoder<C>, dd: Decoder<D>): Decoder<A & B & C & D>; // prettier-ignore
  static intersection <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>; // prettier-ignore
  static intersection <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>; // prettier-ignore
  static intersection <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>; // prettier-ignore
  static intersection <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>; // prettier-ignore
  static intersection(ad: Decoder<any>, bd: Decoder<any>, ...ds: Decoder<any>[]): Decoder<any> {
    return new Decoder((json: unknown) =>
      [ad, bd, ...ds].reduce(
        (acc: DecodeResult<any>, decoder) => Result.map2(Object.assign, acc, decoder.decode(json)),
        Result.ok({})
      )
    );
  }

  /**
   * Decoder that always succeeds with either the decoded value, or a fallback
   * default value.
   */
  static withDefault = <A>(defaultValue: A, decoder: Decoder<A>): Decoder<A> =>
    new Decoder<A>((json: unknown) =>
      Result.ok(Result.withDefault(defaultValue, decoder.decode(json)))
    );

  /**
   * 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}
   * ```
   */
  static valueAt = <A>(paths: (string | number)[], decoder: Decoder<A>): Decoder<A> =>
    new Decoder<A>((json: unknown) => {
      let jsonAtPath: any = json;
      for (let i: number = 0; i < paths.length; i++) {
        if (jsonAtPath === undefined) {
          return Result.err({
            at: printPath(paths.slice(0, i + 1)),
            message: 'path does not exist'
          });
        } else if (typeof paths[i] === 'string' && !isJsonObject(jsonAtPath)) {
          return Result.err({
            at: printPath(paths.slice(0, i + 1)),
            message: expectedGot('an object', jsonAtPath)
          });
        } else if (typeof paths[i] === 'number' && !isJsonArray(jsonAtPath)) {
          return Result.err({
            at: printPath(paths.slice(0, i + 1)),
            message: expectedGot('an array', jsonAtPath)
          });
        } else {
          jsonAtPath = jsonAtPath[paths[i]];
        }
      }
      return Result.mapError(
        error =>
          jsonAtPath === undefined
            ? {at: printPath(paths), message: 'path does not exist'}
            : prependAt(printPath(paths), error),
        decoder.decode(jsonAtPath)
      );
    });

  /**
   * Decoder that ignores the input json and always succeeds with `fixedValue`.
   */
  static succeed = <A>(fixedValue: A): Decoder<A> =>
    new Decoder<A>((json: unknown) => Result.ok(fixedValue));

  /**
   * Decoder that ignores the input json and always fails with `errorMessage`.
   */
  static fail = <A>(errorMessage: string): Decoder<A> =>
    new Decoder<A>((json: unknown) => Result.err({message: errorMessage}));

  /**
   * 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))
   * });
   * ```
   */
  static lazy = <A>(mkDecoder: () => Decoder<A>): Decoder<A> =>
    new Decoder((json: unknown) => mkDecoder().decode(json));

  /**
   * 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'
   * //   }
   * // }
   * ```
   */
  run = (json: unknown): RunResult<A> =>
    Result.mapError(
      error => ({
        kind: 'DecoderError' as 'DecoderError',
        input: json,
        at: 'input' + (error.at || ''),
        message: error.message || ''
      }),
      this.decode(json)
    );

  /**
   * Run the decoder as a `Promise`.
   */
  runPromise = (json: unknown): Promise<A> => Result.asPromise(this.run(json));

  /**
   * Run the decoder and return the value on success, or throw an exception
   * with a formatted error string.
   */
  runWithException = (json: unknown): A => Result.withException(this.run(json));

  /**
   * 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}
   * ```
   */
  map = <B>(f: (value: A) => B): Decoder<B> =>
    new Decoder<B>((json: unknown) => Result.map(f, this.decode(json)));

  /**
   * 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`)
   *   );
   * ```
   */
  andThen = <B>(f: (value: A) => Decoder<B>): Decoder<B> =>
    new Decoder<B>((json: unknown) =>
      Result.andThen(value => f(value).decode(json), this.decode(json))
    );

  /**
   * 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'}}
   * ```
   */
  where = (test: (value: A) => boolean, errorMessage: string): Decoder<A> =>
    this.andThen((value: A) => (test(value) ? Decoder.succeed(value) : Decoder.fail(errorMessage)));
}


================================================
FILE: src/index.ts
================================================
import * as Result from './result';
export {Result};

export {Decoder, DecoderError, isDecoderError, DecoderObject} from './decoder';

export {
  string,
  number,
  boolean,
  anyJson,
  unknownJson,
  constant,
  object,
  array,
  tuple,
  dict,
  optional,
  oneOf,
  union,
  intersection,
  withDefault,
  valueAt,
  succeed,
  fail,
  lazy
} from './combinators';


================================================
FILE: src/result.ts
================================================
/**
 * The result of a computation that may fail. The decoding function
 * `Decoder.run` returns a `Result`. The value of a `Result` is either `Ok` if
 * the computation succeeded, or `Err` if there was some failure in the
 * process.
 */
export type Result<V, E> = Ok<V> | Err<E>;

/**
 * The success type variant for `Result`. Denotes that a result value was
 * computed with no errors.
 */
export interface Ok<V> {
  ok: true;
  result: V;
}

/**
 * The error type variant for `Result`. Denotes that some error occurred before
 * the result was computed.
 */
export interface Err<E> {
  ok: false;
  error: E;
}

/**
 * Wraps values in an `Ok` type.
 *
 * Example: `ok(5) // => {ok: true, result: 5}`
 */
export const ok = <V>(result: V): Ok<V> => ({ok: true, result: result});

/**
 * Typeguard for `Ok`.
 */
export const isOk = <V>(r: Result<V, any>): r is Ok<V> => r.ok === true;

/**
 * Wraps errors in an `Err` type.
 *
 * Example: `err('on fire') // => {ok: false, error: 'on fire'}`
 */
export const err = <E>(error: E): Err<E> => ({ok: false, error: error});

/**
 * Typeguard for `Err`.
 */
export const isErr = <E>(r: Result<any, E>): r is Err<E> => r.ok === false;

/**
 * Create a `Promise` that either resolves with the result of `Ok` or rejects
 * with the error of `Err`.
 */
export const asPromise = <V>(r: Result<V, any>): Promise<V> =>
  r.ok === true ? Promise.resolve(r.result) : Promise.reject(r.error);

/**
 * Unwraps a `Result` and returns either the result of an `Ok`, or
 * `defaultValue`.
 *
 * Example:
 * ```
 * Result.withDefault(5, number().run(json))
 * ```
 *
 * It would be nice if `Decoder` had an instance method that mirrored this
 * function. Such a method would look something like this:
 * ```
 * class Decoder<A> {
 *   runWithDefault = (defaultValue: A, json: any): A =>
 *     Result.withDefault(defaultValue, this.run(json));
 * }
 *
 * number().runWithDefault(5, json)
 * ```
 * Unfortunately, the type of `defaultValue: A` on the method causes issues
 * with type inference on  the `object` decoder in some situations. While these
 * inference issues can be solved by providing the optional type argument for
 * `object`s, the extra trouble and confusion doesn't seem worth it.
 */
export const withDefault = <V>(defaultValue: V, r: Result<V, any>): V =>
  r.ok === true ? r.result : defaultValue;

/**
 * Return the successful result, or throw an error.
 */
export const withException = <V>(r: Result<V, any>): V => {
  if (r.ok === true) {
    return r.result;
  } else {
    throw r.error;
  }
};

/**
 * Given an array of `Result`s, return the successful values.
 */
export const successes = <A>(results: Result<A, any>[]): A[] =>
  results.reduce((acc: A[], r: Result<A, any>) => (r.ok === true ? acc.concat(r.result) : acc), []);

/**
 * Apply `f` to the result of an `Ok`, or pass the error through.
 */
export const map = <A, B, E>(f: (value: A) => B, r: Result<A, E>): Result<B, E> =>
  r.ok === true ? ok<B>(f(r.result)) : r;

/**
 * Apply `f` to the result of two `Ok`s, or pass an error through. If both
 * `Result`s are errors then the first one is returned.
 */
export const map2 = <A, B, C, E>(f: (av: A, bv: B) => C, ar: Result<A, E>, br: Result<B, E>): Result<C, E> =>
  ar.ok === false ? ar :
    br.ok === false ? br :
      ok<C>(f(ar.result, br.result));

/**
 * Apply `f` to the error of an `Err`, or pass the success through.
 */
export const mapError = <V, A, B>(f: (error: A) => B, r: Result<V, A>): Result<V, B> =>
  r.ok === true ? r : err<B>(f(r.error));

/**
 * Chain together a sequence of computations that may fail, similar to a
 * `Promise`. If the first computation fails then the error will propagate
 * through. If it succeeds, then `f` will be applied to the value, returning a
 * new `Result`.
 */
export const andThen = <A, B, E>(f: (value: A) => Result<B, E>, r: Result<A, E>): Result<B, E> =>
  r.ok === true ? f(r.result) : r;


================================================
FILE: test/json-decode.test.ts
================================================
import {
  Decoder,
  Result,
  isDecoderError,
  string,
  number,
  boolean,
  anyJson,
  unknownJson,
  constant,
  object,
  array,
  dict,
  optional,
  oneOf,
  union,
  intersection,
  withDefault,
  valueAt,
  succeed,
  tuple,
  fail,
  lazy
} from '../src/index';

describe('string', () => {
  const decoder = string();

  it('succeeds when given a string', () => {
    expect(decoder.run('hey')).toEqual({ok: true, result: 'hey'});
  });

  it('fails when given a number', () => {
    expect(decoder.run(1)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a string, got a number'}
    });
  });

  it('fails when given null', () => {
    expect(decoder.run(null)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a string, got null'}
    });
  });

  it('fails when given a boolean', () => {
    expect(decoder.run(true)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a string, got a boolean'}
    });
  });
});

describe('number', () => {
  const decoder = number();

  it('succeeds when given a number', () => {
    expect(decoder.run(5)).toEqual({ok: true, result: 5});
  });

  it('fails when given a string', () => {
    expect(decoder.run('hey')).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a number, got a string'}
    });
  });

  it('fails when given boolean', () => {
    expect(decoder.run(true)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a number, got a boolean'}
    });
  });
});

describe('boolean', () => {
  const decoder = boolean();

  it('succeeds when given a boolean', () => {
    expect(decoder.run(true)).toEqual({ok: true, result: true});
  });

  it('fails when given a string', () => {
    expect(decoder.run('hey')).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a boolean, got a string'}
    });
  });

  it('fails when given a number', () => {
    expect(decoder.run(1)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected a boolean, got a number'}
    });
  });
});

describe('anyJson', () => {
  it('bypasses type validation', () => {
    // in a real use case this could be a deeply nested object
    type ComplexType = number;

    interface User {
      name: string;
      complexUserData: ComplexType;
    }

    const userDecoder: Decoder<User> = object({
      name: string(),
      complexUserData: anyJson()
    });

    expect(userDecoder.run({name: 'Wanda', complexUserData: true})).toEqual({
      ok: true,
      result: {name: 'Wanda', complexUserData: true}
    });

    expect(userDecoder.run({name: 'Willard', complexUserData: 'trash data'})).toEqual({
      ok: true,
      result: {name: 'Willard', complexUserData: 'trash data'}
    });

    expect(userDecoder.run({name: 73, complexUserData: []})).toMatchObject({
      ok: false,
      error: {at: 'input.name', message: 'expected a string, got a number'}
    });
  });
});

describe('unknownJson', () => {
  it('accepts any values', () => {
    expect(unknownJson().run(1)).toEqual({ok: true, result: 1});
    expect(unknownJson().run(false)).toEqual({ok: true, result: false});
    expect(unknownJson().run({boots: 'n cats'})).toEqual({ok: true, result: {boots: 'n cats'}});
  });
});

describe('constant', () => {
  it('works for string-literals', () => {
    const decoder: Decoder<'zero'> = constant('zero');

    expect(decoder.run('zero')).toEqual({ok: true, result: 'zero'});
  });

  it('fails when given two different values', () => {
    const decoder: Decoder<42> = constant(42);

    expect(decoder.run(true)).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected 42, got true'}
    });
  });

  it('can decode the true-literal type', () => {
    interface TrueValue {
      x: true;
    }
    const decoder: Decoder<TrueValue> = object({x: constant(true)});

    expect(decoder.run({x: true})).toEqual({ok: true, result: {x: true}});
  });

  it('can decode the false-literal type', () => {
    interface FalseValue {
      x: false;
    }
    const decoder: Decoder<FalseValue> = object({x: constant(false)});

    expect(decoder.run({x: false})).toEqual({ok: true, result: {x: false}});
  });

  it('can decode the null-literal type', () => {
    interface NullValue {
      x: null;
    }
    const decoder: Decoder<NullValue> = object({x: constant(null)});

    expect(decoder.run({x: null})).toEqual({ok: true, result: {x: null}});
  });

  it('can decode a constant array', () => {
    const decoder: Decoder<[1, 2, 3]> = constant([1, 2, 3]);

    expect(decoder.run([1, 2, 3])).toEqual({ok: true, result: [1, 2, 3]});
    expect(decoder.run([1, 2, 3, 4])).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected [1,2,3], got [1,2,3,4]'}
    });
  });

  it('can decode a constant object', () => {
    const decoder: Decoder<{a: true; b: 12}> = constant({a: true, b: 12});

    expect(decoder.run({a: true, b: 12})).toEqual({ok: true, result: {a: true, b: 12}});
    expect(decoder.run({a: true, b: 7})).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected {"a":true,"b":12}, got {"a":true,"b":7}'}
    });
  });
});

describe('object', () => {
  describe('when given valid JSON', () => {
    it('can decode a simple object', () => {
      const decoder = object({x: number()});

      expect(decoder.run({x: 5})).toMatchObject({ok: true, result: {x: 5}});
    });

    it('can decode a nested object', () => {
      const decoder = object({
        payload: object({x: number(), y: number()}),
        error: constant(false)
      });
      const json = {payload: {x: 5, y: 2}, error: false};

      expect(decoder.run(json)).toEqual({ok: true, result: json});
    });
  });

  describe('when given incorrect JSON', () => {
    it('fails when not given an object', () => {
      const decoder = object({x: number()});

      expect(decoder.run('true')).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected an object, got a string'}
      });
    });

    it('fails when given an array', () => {
      const decoder = object({x: number()});

      expect(decoder.run([])).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected an object, got an array'}
      });
    });

    it('reports a missing key', () => {
      const decoder = object({x: number()});

      expect(decoder.run({})).toMatchObject({
        ok: false,
        error: {at: 'input', message: "the key 'x' is required but was not present"}
      });
    });

    it('reports invalid values', () => {
      const decoder = object({name: string()});

      expect(decoder.run({name: 5})).toMatchObject({
        ok: false,
        error: {at: 'input.name', message: 'expected a string, got a number'}
      });
    });

    it('properly displays nested errors', () => {
      const decoder = object({
        hello: object({
          hey: object({
            'Howdy!': string()
          })
        })
      });

      const error = decoder.run({hello: {hey: {'Howdy!': {}}}});
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input.hello.hey.Howdy!', message: 'expected a string, got an object'}
      });
    });
  });

  it('ignores optional fields that decode to undefined', () => {
    const decoder = object({
      a: number(),
      b: optional(string())
    });

    expect(decoder.run({a: 12, b: 'hats'})).toEqual({ok: true, result: {a: 12, b: 'hats'}});
    expect(decoder.run({a: 12})).toEqual({ok: true, result: {a: 12}});
  });

  it('decodes any object when the object shape is not specified', () => {
    const objectKeysDecoder: Decoder<string[]> = object().map(Object.keys);

    expect(objectKeysDecoder.run({n: 1, i: [], c: {}, e: 'e'})).toEqual({
      ok: true,
      result: ['n', 'i', 'c', 'e']
    });
  });
});

describe('array', () => {
  const decoder = array(number());

  it('works when given an array', () => {
    expect(decoder.run([1, 2, 3])).toEqual({ok: true, result: [1, 2, 3]});
  });

  it('fails when given something other than a array', () => {
    expect(decoder.run('oops')).toMatchObject({
      ok: false,
      error: {at: 'input', message: 'expected an array, got a string'}
    });
  });

  describe('when given something other than an array', () => {
    it('fails when the elements are of the wrong type', () => {
      expect(decoder.run(['dang'])).toMatchObject({
        ok: false,
        error: {at: 'input[0]', message: 'expected a number, got a string'}
      });
    });

    it('properly displays nested errors', () => {
      const nestedDecoder = array(array(array(number())));

      expect(nestedDecoder.run([[], [], [[1, 2, 3, false]]])).toMatchObject({
        ok: false,
        error: {at: 'input[2][0][3]', message: 'expected a number, got a boolean'}
      });
    });
  });

  it('decodes any array when the array members decoder is not specified', () => {
    const validNumbersDecoder = array()
      .map((arr: unknown[]) => arr.map(number().run))
      .map(Result.successes);

    expect(validNumbersDecoder.run([1, true, 2, 3, 'five', 4, []])).toEqual({
      ok: true,
      result: [1, 2, 3, 4]
    });

    expect(validNumbersDecoder.run([false, 'hi', {}])).toEqual({ok: true, result: []});

    expect(validNumbersDecoder.run(false)).toMatchObject({
      ok: false,
      error: {message: 'expected an array, got a boolean'}
    });
  });
});

describe('tuple', () => {
  describe('when given valid JSON', () => {
    it('can decode a simple tuple', () => {
      const decoder: Decoder<[number, number]> = tuple([number(), number()]);

      expect(decoder.run([5, 6])).toMatchObject({ok: true, result: [5, 6]});
    });

    it('can decode tuples of mixed types', () => {
      const decoder: Decoder<[number, string]> = tuple([number(), string()]);

      expect(decoder.run([1, 'a'])).toMatchObject({ok: true, result: [1, 'a']});
    });

    it('can decode a nested object', () => {
      const decoder: Decoder<[{x: number; y: number}, false]> = tuple([
        object({x: number(), y: number()}),
        constant(false)
      ]);
      const json = [{x: 5, y: 2}, false];

      expect(decoder.run(json)).toEqual({ok: true, result: json});
    });
  });

  describe('when given incorrect JSON', () => {
    it('fails when the array length does not match', () => {
      const decoder: Decoder<[number]> = tuple([number()]);

      expect(decoder.run([1, 2])).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected a tuple of length 1, got one of length 2'}
      });
    });

    it('fails when given an object', () => {
      const decoder: Decoder<[number]> = tuple([number()]);

      expect(decoder.run({x: 1})).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected a tuple of length 1, got an object'}
      });
    });

    it('reports invalid values', () => {
      const decoder: Decoder<[number, string]> = tuple([number(), string()]);

      expect(decoder.run([4, 5])).toMatchObject({
        ok: false,
        error: {at: 'input[1]', message: 'expected a string, got a number'}
      });
    });

    it('properly displays nested errors', () => {
      const decoder: Decoder<[{hey: {'Howdy!': string}}]> = tuple([
        object({
          hey: object({
            'Howdy!': string()
          })
        })
      ]);

      const error = decoder.run([{hey: {'Howdy!': {}}}]);
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input[0].hey.Howdy!', message: 'expected a string, got an object'}
      });
    });
  });
});

describe('dict', () => {
  describe('with a simple value decoder', () => {
    const decoder = dict(number());

    it('can decode an empty object', () => {
      expect(decoder.run({})).toEqual({ok: true, result: {}});
    });

    it('can decode an object of with arbitrary keys', () => {
      expect(decoder.run({a: 1, b: 2})).toEqual({ok: true, result: {a: 1, b: 2}});
    });

    it('fails if a value cannot be decoded', () => {
      expect(decoder.run({oh: 'no'})).toMatchObject({
        ok: false,
        error: {at: 'input.oh', message: 'expected a number, got a string'}
      });
    });

    it('fails if given an array', () => {
      expect(decoder.run([])).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected an object, got an array'}
      });
    });

    it('fails if given a primitive', () => {
      expect(decoder.run(5)).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected an object, got a number'}
      });
    });
  });

  describe('given a transformative value decoder', () => {
    const decoder = dict(string().map(str => str + '!'));

    it('transforms the values', () => {
      expect(decoder.run({hey: 'there', yo: 'dude'})).toEqual({
        ok: true,
        result: {hey: 'there!', yo: 'dude!'}
      });
    });
  });
});

describe('optional', () => {
  describe('decoding a non-object type', () => {
    const decoder = optional(number());

    it('can decode the given type', () => {
      expect(decoder.run(5)).toEqual({ok: true, result: 5});
    });

    it('can decode undefined', () => {
      expect(decoder.run(undefined)).toEqual({ok: true, result: undefined});
    });

    it('fails when the value is invalid', () => {
      expect(decoder.run(false)).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected a number, got a boolean'}
      });
    });
  });

  describe('decoding an interface with optional fields', () => {
    interface User {
      id: number;
      isDog?: boolean;
    }

    const decoder: Decoder<User> = object({
      id: number(),
      isDog: optional(boolean())
    });

    it('can decode the object when the optional field is present', () => {
      expect(decoder.run({id: 1, isDog: true})).toEqual({ok: true, result: {id: 1, isDog: true}});
    });

    it('can decode the object when the optional field is missing', () => {
      expect(decoder.run({id: 2})).toEqual({ok: true, result: {id: 2}});
    });

    it('fails when the optional field is invalid', () => {
      const error = decoder.run({id: 3, isDog: 'supdog'});
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input.isDog', message: 'expected a boolean, got a string'}
      });
    });
  });
});

describe('oneOf', () => {
  describe('when given valid input', () => {
    it('can decode a value with a single alternative', () => {
      const decoder = oneOf(string());

      expect(decoder.run('yo')).toEqual({ok: true, result: 'yo'});
    });

    it('can decode a value with multiple alternatives', () => {
      const decoder = array(oneOf(string().map(s => s.length), number()));

      expect(decoder.run(['hey', 10])).toEqual({ok: true, result: [3, 10]});
    });
  });

  it('fails when a value does not match any decoder', () => {
    const decoder = oneOf(string(), number().map(String));

    expect(decoder.run([])).toMatchObject({
      ok: false,
      error: {
        at: 'input',
        message:
          'expected a value matching one of the decoders, got the errors ' +
          '["at error: expected a string, got an array", "at error: expected a number, got an array"]'
      }
    });
  });

  it('fails and reports errors for nested values', () => {
    const decoder = array(
      oneOf(valueAt([1, 'a', 'b'], number()), valueAt([1, 'a', 'x'], number()))
    );

    expect(decoder.run([[{}, {a: {b: true}}]])).toMatchObject({
      ok: false,
      error: {
        at: 'input[0]',
        message:
          'expected a value matching one of the decoders, got the errors ' +
          '["at error[1].a.b: expected a number, got a boolean", ' +
          '"at error[1].a.x: path does not exist"]'
      }
    });
  });

  it('can act as the union function when given the correct annotation', () => {
    type C = {a: string} | {b: number};

    const decoder: Decoder<C> = oneOf(object<C>({a: string()}), object<C>({b: number()}));

    expect(decoder.run({a: 'xyz'})).toEqual({ok: true, result: {a: 'xyz'}});
  });
});

describe('union', () => {
  interface A {
    kind: 'a';
    value: number;
  }
  interface B {
    kind: 'b';
    value: boolean;
  }
  type C = A | B;

  const decoder: Decoder<C> = union(
    object({kind: constant('a'), value: number()}),
    object({kind: constant('b'), value: boolean()})
  );

  it('can decode a value that matches one of the union types', () => {
    const json = {kind: 'a', value: 12};
    expect(decoder.run(json)).toEqual({ok: true, result: json});
  });

  it('fails when a value does not match any decoders', () => {
    const error = decoder.run({kind: 'b', value: 12});
    expect(error).toMatchObject({
      ok: false,
      error: {
        at: 'input',
        message:
          'expected a value matching one of the decoders, got the errors ' +
          '["at error.kind: expected "a", got "b"", "at error.value: expected a boolean, got a number"]'
      }
    });
  });
});

describe('intersection', () => {
  it('uses two decoders to decode an extended interface', () => {
    interface A {
      a: number;
    }

    interface AB extends A {
      b: string;
    }

    const aDecoder: Decoder<A> = object({a: number()});
    const abDecoder: Decoder<AB> = intersection(aDecoder, object({b: string()}));

    expect(abDecoder.run({a: 12, b: '!!!'})).toEqual({ok: true, result: {a: 12, b: '!!!'}});
  });

  it('can combine many decoders', () => {
    interface UVWXYZ {
      u: true;
      v: string[];
      w: boolean | null;
      x: number;
      y: string;
      z: boolean;
    }

    const uvwxyzDecoder: Decoder<UVWXYZ> = intersection(
      object({u: constant(true)}),
      object({v: array(string())}),
      object({w: union(boolean(), constant(null))}),
      object({x: number()}),
      object({y: string(), z: boolean()})
    );

    expect(uvwxyzDecoder.run({u: true, v: [], w: null, x: 4, y: 'y', z: false})).toEqual({
      ok: true,
      result: {u: true, v: [], w: null, x: 4, y: 'y', z: false}
    });
  });
});

describe('withDefault', () => {
  const decoder = withDefault('puppies', string());

  it('uses the json value when decoding is successful', () => {
    expect(decoder.run('pancakes')).toEqual({ok: true, result: 'pancakes'});
  });

  it('uses the default when the decoder fails', () => {
    expect(decoder.run(5)).toEqual({ok: true, result: 'puppies'});
  });
});

describe('valueAt', () => {
  describe('decode an value', () => {
    it('can decode a single object field', () => {
      const decoder = valueAt(['a'], string());
      expect(decoder.run({a: 'boots', b: 'cats'})).toEqual({ok: true, result: 'boots'});
    });

    it('can decode a single array value', () => {
      const decoder = valueAt([1], string());
      expect(decoder.run(['boots', 'cats'])).toEqual({ok: true, result: 'cats'});
    });
  });

  describe('decode a nested path', () => {
    const decoder = valueAt(['a', 1, 'b'], string());

    it('can decode a field in a nested structure', () => {
      expect(decoder.run({a: [{}, {b: 'surprise!'}]})).toEqual({ok: true, result: 'surprise!'});
    });

    it('fails when an array path does not exist', () => {
      expect(decoder.run({a: []})).toMatchObject({
        ok: false,
        error: {at: 'input.a[1].b', message: 'path does not exist'}
      });
    });

    it('fails when an object path does not exist', () => {
      expect(decoder.run({x: 12})).toMatchObject({
        ok: false,
        error: {at: 'input.a[1]', message: 'path does not exist'}
      });
    });

    it('fails when the decoder fails at the end of the path', () => {
      expect(decoder.run({a: ['a', {b: 12}]})).toMatchObject({
        ok: false,
        error: {at: 'input.a[1].b', message: 'expected a string, got a number'}
      });
    });
  });

  describe('decode an optional field', () => {
    const decoder = valueAt(['a', 'b', 'c'], optional(string()));

    it('fails when the path does not exist', () => {
      const error = decoder.run({a: {x: 'cats'}});
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input.a.b.c', message: 'path does not exist'}
      });
    });

    it('succeeds when the final field is not found', () => {
      expect(decoder.run({a: {b: {z: 1}}})).toEqual({ok: true, result: undefined});
    });
  });

  describe('non-object json', () => {
    it('only accepts json objects and arrays', () => {
      const decoder = valueAt(['a'], string());

      expect(decoder.run('abc')).toMatchObject({
        ok: false,
        error: {at: 'input.a', message: 'expected an object, got a string'}
      });
      expect(decoder.run(true)).toMatchObject({
        ok: false,
        error: {at: 'input.a', message: 'expected an object, got a boolean'}
      });
    });

    it('fails when a feild in the path does not correspond to a json object', () => {
      const decoder = valueAt(['a', 'b', 'c'], string());

      const error = decoder.run({a: {b: 1}});
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input.a.b.c', message: 'expected an object, got a number'}
      });
    });

    it('fails when an index in the path does not correspond to a json array', () => {
      const decoder = valueAt([0, 0, 1], string());

      const error = decoder.run([[false]]);
      expect(error).toMatchObject({
        ok: false,
        error: {at: 'input[0][0][1]', message: 'expected an array, got a boolean'}
      });
    });
  });

  it('decodes the input when given an empty path', () => {
    const decoder = valueAt([], number());

    expect(decoder.run(12)).toEqual({ok: true, result: 12});
  });
});

describe('succeed', () => {
  const decoder = succeed(12345);

  it('always decodes the input as the same value', () => {
    expect(decoder.run('pancakes')).toEqual({ok: true, result: 12345});
    expect(decoder.run(5)).toEqual({ok: true, result: 12345});
  });
});

describe('fail', () => {
  const wisdom = 'People don’t think it be like it is, but it do.';
  const decoder = fail(wisdom);

  it('always fails and returns the same error message', () => {
    expect(decoder.run('pancakes')).toMatchObject({
      ok: false,
      error: {at: 'input', message: wisdom}
    });
    expect(decoder.run(5)).toMatchObject({ok: false, error: {at: 'input', message: wisdom}});
  });
});

describe('lazy', () => {
  describe('decoding a primitive data type', () => {
    const decoder = lazy(() => string());

    it('can decode type as normal', () => {
      expect(decoder.run('hello')).toEqual({ok: true, result: 'hello'});
    });

    it('does not alter the error message', () => {
      expect(decoder.run(5)).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'expected a string, got a number'}
      });
    });
  });

  describe('decoding a recursive data structure', () => {
    interface Comment {
      msg: string;
      replies: Comment[];
    }

    const decoder: Decoder<Comment> = object({
      msg: string(),
      replies: lazy(() => array(decoder))
    });

    it('can decode the data structure', () => {
      const tree = {msg: 'hey', replies: [{msg: 'hi', replies: []}]};

      expect(decoder.run(tree)).toEqual({
        ok: true,
        result: {msg: 'hey', replies: [{msg: 'hi', replies: []}]}
      });
    });

    it('fails when a nested value is invalid', () => {
      const badTree = {msg: 'hey', replies: [{msg: 'hi', replies: ['hello']}]};

      expect(decoder.run(badTree)).toMatchObject({
        ok: false,
        error: {at: 'input.replies[0].replies[0]', message: 'expected an object, got a string'}
      });
    });
  });
});

describe('runPromise', () => {
  const promise = (json: unknown): Promise<boolean> => boolean().runPromise(json);

  it('resolves the promise when the decoder succeeds', () => {
    return expect(promise(true)).resolves.toBe(true);
  });

  it('rejects the promise when the decoder fails', () => {
    return expect(promise(42)).rejects.toEqual({
      kind: 'DecoderError',
      input: 42,
      at: 'input',
      message: 'expected a boolean, got a number'
    });
  });

  it('returns a DecoderError when the decoder fails', () => {
    return expect(promise(42).catch(e => isDecoderError(e))).resolves.toBeTruthy();
  });
});

describe('runWithException', () => {
  const decoder = boolean();

  it('can run a decoder and return the successful value', () => {
    expect(decoder.runWithException(false)).toBe(false);
  });

  it('throws an exception when the decoder fails', () => {
    let thrownError: any;

    try {
      decoder.runWithException(42);
    } catch (e) {
      thrownError = e;
    }

    expect(thrownError).toEqual({
      kind: 'DecoderError',
      input: 42,
      at: 'input',
      message: 'expected a boolean, got a number'
    });
  });
});

describe('map', () => {
  it('can apply the identity function to the decoder', () => {
    const decoder = string().map(x => x);

    expect(decoder.run('hey there')).toEqual({ok: true, result: 'hey there'});
  });

  it('can apply an endomorphic function to the decoder', () => {
    const decoder = number().map(x => x * 5);

    expect(decoder.run(10)).toEqual({ok: true, result: 50});
  });

  it('can apply a function that transforms the type', () => {
    const decoder = string().map(x => x.length);

    expect(decoder.run('hey')).toEqual({ok: true, result: 3});
  });
});

describe('andThen', () => {
  describe('creates decoders based on previous results', () => {
    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.`);
      }
    });

    it('can decode using both the first and second decoder', () => {
      expect(decoder.run({version: 5, x: 'bootsncats'})).toMatchObject({
        ok: false,
        error: {at: 'input', message: 'Unable to decode info, version 5 is not supported.'}
      });

      expect(decoder.run({version: 3, a: true})).toEqual({ok: true, result: {a: true}});
    });

    it('fails when the first decoder fails', () => {
      expect(decoder.run({version: null, a: true})).toMatchObject({
        ok: false,
        error: {at: 'input.version', message: 'expected a number, got null'}
      });
    });

    it('fails when the second decoder fails', () => {
      const json = {version: 3, a: 1};
      expect(decoder.run(json)).toMatchObject({
        ok: false,
        error: {at: 'input.a', message: 'expected a boolean, got a number'}
      });
    });
  });

  it('creates decoders for custom types', () => {
    type NonEmptyArray<T> = T[] & {__nonEmptyArrayBrand__: void};
    const createNonEmptyArray = <T>(arr: T[]): NonEmptyArray<T> => arr as NonEmptyArray<T>;

    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`)
      );

    expect(nonEmptyArrayDecoder(number()).run([1, 2, 3])).toEqual({
      ok: true,
      result: [1, 2, 3]
    });

    expect(nonEmptyArrayDecoder(number()).run([])).toMatchObject({
      ok: false,
      error: {message: 'expected a non-empty array, got an empty array'}
    });
  });
});

describe('where', () => {
  const chars = (length: number): Decoder<string> =>
    string().where((s: string) => s.length === length, `expected a string of length ${length}`);

  const range = (min: number, max: number): Decoder<number> =>
    number().where(
      (n: number) => n >= min && n <= max,
      `expected a number between ${min} and ${max}`
    );

  it('can test for strings of a given length', () => {
    expect(chars(7).run('7777777')).toEqual({ok: true, result: '7777777'});

    expect(chars(7).run('666666')).toMatchObject({
      ok: false,
      error: {message: 'expected a string of length 7'}
    });
  });

  it('can test for numbers in a given range', () => {
    expect(range(1, 9).run(7)).toEqual({ok: true, result: 7});

    expect(range(1, 9).run(12)).toMatchObject({
      ok: false,
      error: {message: 'expected a number between 1 and 9'}
    });
  });

  it('reports when the base decoder fails', () => {
    expect(chars(7).run(false)).toMatchObject({
      ok: false,
      error: {message: 'expected a string, got a boolean'}
    });

    expect(range(0, 1).run(null)).toMatchObject({
      ok: false,
      error: {message: 'expected a number, got null'}
    });
  });
});

describe('Result', () => {
  describe('can run a decoder with default value', () => {
    const decoder = number();

    it('succeeds with the value', () => {
      expect(Result.withDefault(0, decoder.run(12))).toEqual(12);
    });

    it('succeeds with the default value instead of failing', () => {
      expect(Result.withDefault(0, decoder.run('999'))).toEqual(0);
    });
  });

  it('can return successes from an array of decoded values', () => {
    const json: unknown = [1, true, 2, 3, 'five', 4, []];
    const jsonArray: unknown[] = Result.withDefault([], array().run(json));
    const numbers: number[] = Result.successes(jsonArray.map(number().run));

    expect(numbers).toEqual([1, 2, 3, 4]);
  });
});


================================================
FILE: test/phone-example.test.ts
================================================
import {
  Decoder,
  string,
  number,
  constant,
  object,
  array,
  optional,
  oneOf,
  union
} from '../src/index';

describe('decode phone number objects', () => {
  enum PhoneUse {
    Mobile = 'Mobile',
    Home = 'Home',
    Work = 'Work'
  }

  interface PhoneNumber {
    id: number;
    use?: PhoneUse;
  }

  interface InternationalPhone extends PhoneNumber {
    international: true;
    rawNumber: string;
  }

  interface DomesticPhone extends PhoneNumber {
    international: false;
    areaCode: string;
    prefix: string;
    lineNumber: string;
  }

  type Phone = DomesticPhone | InternationalPhone;

  const phoneUseDecoder: Decoder<PhoneUse> = oneOf(
    constant(PhoneUse.Mobile),
    constant(PhoneUse.Home),
    constant(PhoneUse.Work)
  );

  const internationalPhoneDecoder: Decoder<InternationalPhone> = object({
    id: number(),
    use: optional(phoneUseDecoder),
    international: constant(true),
    rawNumber: string()
  });

  const domesticPhoneDecoder: Decoder<DomesticPhone> = object({
    id: number(),
    use: optional(phoneUseDecoder),
    international: constant(false),
    areaCode: string(),
    prefix: string(),
    lineNumber: string()
  });

  const phoneDecoder: Decoder<Phone> = union(domesticPhoneDecoder, internationalPhoneDecoder);

  const phonesDecoder: Decoder<Phone[]> = array(phoneDecoder);

  it('can decode both international and domestic phones', () => {
    const json = [
      {
        id: 1,
        use: 'Work',
        international: false,
        areaCode: '123',
        prefix: '456',
        lineNumber: '7890'
      },
      {
        id: 2,
        use: 'Work',
        international: true,
        rawNumber: '111234567890'
      },
      {
        id: 3,
        international: false,
        areaCode: '000',
        prefix: '000',
        lineNumber: '5555'
      }
    ];

    expect(phonesDecoder.run(json)).toEqual({ok: true, result: json});
  });

  it('fails when an object is neither an international or domestic phone', () => {
    const json = [
      {
        id: 1,
        use: 'Work',
        international: false,
        areaCode: '123',
        prefix: '456',
        lineNumber: '7890'
      },
      {
        id: 5
      }
    ];

    const error = phonesDecoder.run(json);
    expect(error).toMatchObject({
      ok: false,
      error: {
        at: 'input[1]',
        message: [
          'expected a value matching one of the decoders, got the errors ',
          `["at error: the key 'international' is required but was not present", `,
          `"at error: the key 'international' is required but was not present"]`
        ].join('')
      }
    });
  });
});


================================================
FILE: test/tagged-json-example.test.ts
================================================
import {
  Decoder,
  string,
  number,
  boolean,
  constant,
  array,
  dict,
  union,
  lazy
} from '../src/index';

describe('create tagged json objects', () => {
  type TaggedJson =
    | {tag: 'null'; value: null}
    | {tag: 'string'; value: string}
    | {tag: 'number'; value: number}
    | {tag: 'boolean'; value: boolean}
    | {tag: 'array'; value: Array<TaggedJson>}
    | {tag: 'object'; value: {[name: string]: TaggedJson}};

  const json: any = [{x: 1, y: 5}, {a: true, b: 'false'}, 1, true];

  const taggedJsonDecoder: Decoder<TaggedJson> = union(
    constant(null).map<TaggedJson>(value => ({tag: 'null', value: value})),
    string().map<TaggedJson>(value => ({tag: 'string', value: value})),
    number().map<TaggedJson>(value => ({tag: 'number', value: value})),
    boolean().map<TaggedJson>(value => ({tag: 'boolean', value: value})),
    lazy(() => array(taggedJsonDecoder).map<TaggedJson>(value => ({tag: 'array', value: value}))),
    lazy(() => dict(taggedJsonDecoder).map<TaggedJson>(value => ({tag: 'object', value: value})))
  );

  it('maps json to tagged json', () => {
    expect(taggedJsonDecoder.run(json)).toEqual({
      ok: true,
      result: {
        tag: 'array',
        value: [
          {
            tag: 'object',
            value: {
              x: {tag: 'number', value: 1},
              y: {tag: 'number', value: 5}
            }
          },
          {
            tag: 'object',
            value: {
              a: {
                tag: 'boolean',
                value: true
              },
              b: {
                tag: 'string',
                value: 'false'
              }
            }
          },
          {
            tag: 'number',
            value: 1
          },
          {
            tag: 'boolean',
            value: true
          }
        ]
      }
    });
  });
});


================================================
FILE: test/user-example.test.ts
================================================
import {Decoder, string, number, boolean, object} from '../src/index';

describe('decode json as User interface', () => {
  interface User {
    firstname: string;
    lastname: string;
    age: number;
    active: boolean;
  }

  const userJson: any = {
    firstname: 'John',
    lastname: 'Doe',
    age: 99,
    active: false
  };

  const invalidUserJson: any = {
    firstname: 'John',
    lastName: 'Doe', // invalid camelCase
    age: 99,
    active: false
  };

  const userDecoder: Decoder<User> = object({
    firstname: string(),
    lastname: string(),
    age: number(),
    active: boolean()
  });

  it('successfuly passes through the valid user object', () => {
    expect(userDecoder.run(userJson)).toEqual({
      ok: true,
      result: userJson
    });
  });

  it('fails when a required key is missing', () => {
    const error = userDecoder.run(invalidUserJson);
    expect(error).toMatchObject({
      ok: false,
      error: {at: 'input', message: "the key 'lastname' is required but was not present"}
    });
  });
});


================================================
FILE: tsconfig-test.json
================================================
{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "module": "es2015",
    "lib": ["es2015", "es2016", "es2017", "dom"],
    "strict": true,
    "sourceMap": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declarationDir": "dist/types",
    "outDir": "dist/es",
    "typeRoots": ["node_modules/@types"]
  },
  "include": ["src", "test"]
}


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "module": "es2015",
    "lib": ["es2015", "es2016", "es2017", "dom"],
    "strict": true,
    "sourceMap": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declarationDir": "dist/types",
    "outDir": "dist/es",
    "typeRoots": ["node_modules/@types"]
  },
  "include": ["src"]
}


================================================
FILE: tslint.json
================================================
{
  "extends": [
    "tslint-config-standard",
    "tslint-config-prettier"
  ],
  "rules": {
    "strict-type-predicates": false
  }
}
Download .txt
gitextract_0gr7gt1_/

├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .travis.yml
├── DOCS.md
├── LICENSE
├── README.md
├── bin/
│   └── jtv
├── docs/
│   ├── README.md
│   ├── classes/
│   │   └── _decoder_.decoder.md
│   ├── interfaces/
│   │   ├── _decoder_.decodererror.md
│   │   ├── _result_.err.md
│   │   └── _result_.ok.md
│   └── modules/
│       ├── _combinators_.md
│       ├── _decoder_.md
│       ├── _index_.md
│       └── _result_.md
├── nix-files/
│   ├── default.nix
│   ├── nixpkgs.nix
│   └── shell.nix
├── package.json
├── rollup.config.ts
├── src/
│   ├── combinators.ts
│   ├── decoder.ts
│   ├── index.ts
│   └── result.ts
├── test/
│   ├── json-decode.test.ts
│   ├── phone-example.test.ts
│   ├── tagged-json-example.test.ts
│   └── user-example.test.ts
├── tsconfig-test.json
├── tsconfig.json
└── tslint.json
Download .txt
SYMBOL INDEX (40 symbols across 6 files)

FILE: src/decoder.ts
  type DecoderError (line 9) | interface DecoderError {
  type RunResult (line 21) | type RunResult<A> = Result.Result<A, DecoderError>;
  type DecodeResult (line 28) | type DecodeResult<A> = Result.Result<A, Partial<DecoderError>>;
  type DecoderObject (line 49) | type DecoderObject<A> = {[t in keyof A]: Decoder<A[t]>};
  class Decoder (line 123) | class Decoder<A> {
    method constructor (line 138) | private constructor(private decode: (json: unknown) => DecodeResult<A>...
    method string (line 143) | static string(): Decoder<string> {
    method number (line 155) | static number(): Decoder<number> {
    method boolean (line 167) | static boolean(): Decoder<boolean> {
    method constant (line 236) | static constant(value: any) {
    method object (line 268) | static object<A>(decoders?: DecoderObject<A>) {
    method array (line 329) | static array<A>(decoder?: Decoder<A>) {
    method tuple (line 367) | static tuple<A>(decoders: Decoder<A>[]) {
    method union (line 501) | static union(ad: Decoder<any>, bd: Decoder<any>, ...decoders: Decoder<...
    method intersection (line 530) | static intersection(ad: Decoder<any>, bd: Decoder<any>, ...ds: Decoder...

FILE: src/result.ts
  type Result (line 7) | type Result<V, E> = Ok<V> | Err<E>;
  type Ok (line 13) | interface Ok<V> {
  type Err (line 22) | interface Err<E> {

FILE: test/json-decode.test.ts
  type ComplexType (line 102) | type ComplexType = number;
  type User (line 104) | interface User {
  type TrueValue (line 156) | interface TrueValue {
  type FalseValue (line 165) | interface FalseValue {
  type NullValue (line 174) | interface NullValue {
  type User (line 485) | interface User {
  type C (line 560) | type C = {a: string} | {b: number};
  type A (line 569) | interface A {
  type B (line 573) | interface B {
  type C (line 577) | type C = A | B;
  type A (line 605) | interface A {
  type AB (line 609) | interface AB extends A {
  type UVWXYZ (line 620) | interface UVWXYZ {
  type Comment (line 795) | interface Comment {
  type NonEmptyArray (line 931) | type NonEmptyArray<T> = T[] & {__nonEmptyArrayBrand__: void};

FILE: test/phone-example.test.ts
  type PhoneUse (line 14) | enum PhoneUse {
  type PhoneNumber (line 20) | interface PhoneNumber {
  type InternationalPhone (line 25) | interface InternationalPhone extends PhoneNumber {
  type DomesticPhone (line 30) | interface DomesticPhone extends PhoneNumber {
  type Phone (line 37) | type Phone = DomesticPhone | InternationalPhone;

FILE: test/tagged-json-example.test.ts
  type TaggedJson (line 14) | type TaggedJson =

FILE: test/user-example.test.ts
  type User (line 4) | interface User {
Condensed preview — 34 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (146K chars).
[
  {
    "path": ".gitignore",
    "chars": 108,
    "preview": "node_modules\ncoverage\n.nyc_output\n.DS_Store\n*.log\n.vscode\n.idea\ndist\ncompiled\n.awcache\n.rpt2_cache\ngc-roots\n"
  },
  {
    "path": ".npmignore",
    "chars": 182,
    "preview": ".git/\n.rpt2_cache/\nbin/\ncoverage/\nnix-files/\nnode_modules/\nsrc/\ntest/\n.gitignore\n.prettierrc\n.travis.yml\nrollup.config.t"
  },
  {
    "path": ".prettierignore",
    "chars": 19,
    "preview": "package.json\ndist/\n"
  },
  {
    "path": ".prettierrc",
    "chars": 152,
    "preview": "printWidth: 100\ntabWidth: 2\nuseTabs: false\nsemi: true\nsingleQuote: true\ntrailingComma: none\nbracketSpacing: false\narrowP"
  },
  {
    "path": ".travis.yml",
    "chars": 210,
    "preview": "language: node_js\ncache:\n  yarn: true\n  directories:\n    - node_modules\nnotifications:\n  email: false\nnode_js:\n  - node\n"
  },
  {
    "path": "DOCS.md",
    "chars": 1857,
    "preview": "# Documentation\n\n[Documentation](https://github.com/mojotech/json-type-validation/tree/master/docs).\n\nThe best places to"
  },
  {
    "path": "LICENSE",
    "chars": 1057,
    "preview": "Copyright (c) 2018 Elias Mulhall\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis s"
  },
  {
    "path": "README.md",
    "chars": 4325,
    "preview": "# JSON Type Validation\n\nA [TypeScript](https://www.typescriptlang.org/) library to perform type checking and validation "
  },
  {
    "path": "bin/jtv",
    "chars": 1961,
    "preview": "#!/usr/bin/env bash\n\nSCRIPTNAME=$(basename $0)\nDIRNAME=$(dirname $0)\nMODE=$1\n\nshift\n\nprint_help() {\n    echo \"Usage: $SC"
  },
  {
    "path": "docs/README.md",
    "chars": 2056,
    "preview": "\nDocumentation\n=============\n\n[Documentation](https://github.com/mojotech/json-type-validation/tree/master/docs).\n\nThe b"
  },
  {
    "path": "docs/classes/_decoder_.decoder.md",
    "chars": 37372,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"decoder\"](../modules/_decoder_.md) > [Decoder](../classes/_decoder_.d"
  },
  {
    "path": "docs/interfaces/_decoder_.decodererror.md",
    "chars": 862,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"decoder\"](../modules/_decoder_.md) > [DecoderError](../interfaces/_de"
  },
  {
    "path": "docs/interfaces/_result_.err.md",
    "chars": 510,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"result\"](../modules/_result_.md) > [Err](../interfaces/_result_.err.m"
  },
  {
    "path": "docs/interfaces/_result_.ok.md",
    "chars": 502,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"result\"](../modules/_result_.md) > [Ok](../interfaces/_result_.ok.md)"
  },
  {
    "path": "docs/modules/_combinators_.md",
    "chars": 3649,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"combinators\"](../modules/_combinators_.md)\n\n# External module: \"combi"
  },
  {
    "path": "docs/modules/_decoder_.md",
    "chars": 1375,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"decoder\"](../modules/_decoder_.md)\n\n# External module: \"decoder\"\n\n## "
  },
  {
    "path": "docs/modules/_index_.md",
    "chars": 126,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"index\"](../modules/_index_.md)\n\n# External module: \"index\"\n\n## Index\n"
  },
  {
    "path": "docs/modules/_result_.md",
    "chars": 6659,
    "preview": "[@mojotech/json-type-validation](../README.md) > [\"result\"](../modules/_result_.md)\n\n# External module: \"result\"\n\n## Ind"
  },
  {
    "path": "nix-files/default.nix",
    "chars": 613,
    "preview": "{ nixpkgsFn ? import ./nixpkgs.nix\n, system ? null }:\nlet nixpkgs = nixpkgsFn ({\n      # extra config goes here\n    } //"
  },
  {
    "path": "nix-files/nixpkgs.nix",
    "chars": 315,
    "preview": "let source = ''\n      {\n        \"owner\": \"NixOS\",\n        \"repo\": \"nixpkgs-channels\",\n        \"rev\": \"aebdc892d6aa6834a0"
  },
  {
    "path": "nix-files/shell.nix",
    "chars": 104,
    "preview": "{ nixpkgsFn ? import ./nixpkgs.nix\n, package ? ./default.nix\n}:\n(import package { inherit nixpkgsFn; })\n"
  },
  {
    "path": "package.json",
    "chars": 2584,
    "preview": "{\n  \"name\": \"@mojotech/json-type-validation\",\n  \"version\": \"3.1.0\",\n  \"description\": \"runtime type checking and validati"
  },
  {
    "path": "rollup.config.ts",
    "chars": 733,
    "preview": "import resolve from 'rollup-plugin-node-resolve';\nimport sourceMaps from 'rollup-plugin-sourcemaps';\nimport typescript f"
  },
  {
    "path": "src/combinators.ts",
    "chars": 1410,
    "preview": "import {Decoder} from './decoder';\n\n/* tslint:disable:variable-name */\n\n/** See `Decoder.string` */\nexport const string "
  },
  {
    "path": "src/decoder.ts",
    "chars": 29219,
    "preview": "import * as Result from './result';\nimport isEqual from \"lodash/isEqual\"\n\n/**\n * Information describing how json data fa"
  },
  {
    "path": "src/index.ts",
    "chars": 371,
    "preview": "import * as Result from './result';\nexport {Result};\n\nexport {Decoder, DecoderError, isDecoderError, DecoderObject} from"
  },
  {
    "path": "src/result.ts",
    "chars": 3918,
    "preview": "/**\n * The result of a computation that may fail. The decoding function\n * `Decoder.run` returns a `Result`. The value o"
  },
  {
    "path": "test/json-decode.test.ts",
    "chars": 29595,
    "preview": "import {\n  Decoder,\n  Result,\n  isDecoderError,\n  string,\n  number,\n  boolean,\n  anyJson,\n  unknownJson,\n  constant,\n  o"
  },
  {
    "path": "test/phone-example.test.ts",
    "chars": 2674,
    "preview": "import {\n  Decoder,\n  string,\n  number,\n  constant,\n  object,\n  array,\n  optional,\n  oneOf,\n  union\n} from '../src/index"
  },
  {
    "path": "test/tagged-json-example.test.ts",
    "chars": 1864,
    "preview": "import {\n  Decoder,\n  string,\n  number,\n  boolean,\n  constant,\n  array,\n  dict,\n  union,\n  lazy\n} from '../src/index';\n\n"
  },
  {
    "path": "test/user-example.test.ts",
    "chars": 1045,
    "preview": "import {Decoder, string, number, boolean, object} from '../src/index';\n\ndescribe('decode json as User interface', () => "
  },
  {
    "path": "tsconfig-test.json",
    "chars": 471,
    "preview": "{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"lib\": [\"es201"
  },
  {
    "path": "tsconfig.json",
    "chars": 463,
    "preview": "{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"lib\": [\"es201"
  },
  {
    "path": "tslint.json",
    "chars": 136,
    "preview": "{\n  \"extends\": [\n    \"tslint-config-standard\",\n    \"tslint-config-prettier\"\n  ],\n  \"rules\": {\n    \"strict-type-predicate"
  }
]

About this extraction

This page contains the full source code of the mojotech/json-type-validation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 34 files (135.3 KB), approximately 40.3k tokens, and a symbol index with 40 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!