decoders 2.0.0-beta1 → 2.0.0-beta13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -5
- package/Decoder.d.ts +94 -0
- package/Decoder.js +222 -0
- package/Decoder.js.flow +286 -0
- package/Decoder.mjs +215 -0
- package/NotSupportedTSVersion.d.ts +1 -0
- package/README.md +124 -961
- package/_utils.d.ts +9 -0
- package/{cjs/_utils.js → _utils.js} +12 -18
- package/{cjs/_utils.js.flow → _utils.js.flow} +15 -19
- package/{es/_utils.js → _utils.mjs} +11 -15
- package/{ts/annotate.d.ts → annotate.d.ts} +25 -21
- package/{cjs/annotate.js → annotate.js} +0 -0
- package/{cjs/annotate.js.flow → annotate.js.flow} +0 -0
- package/{es/annotate.js → annotate.mjs} +0 -0
- package/format.d.ts +6 -0
- package/{cjs/format/inline.js → format.js} +7 -2
- package/{cjs/format/inline.js.flow → format.js.flow} +9 -3
- package/{es/format/inline.js → format.mjs} +5 -2
- package/index.d.ts +40 -0
- package/index.js +89 -0
- package/index.js.flow +44 -0
- package/index.mjs +11 -0
- package/{ts → lib}/_helpers.d.ts +0 -0
- package/lib/arrays.d.ts +59 -0
- package/lib/arrays.js +139 -0
- package/lib/arrays.js.flow +138 -0
- package/lib/arrays.mjs +124 -0
- package/lib/basics.d.ts +93 -0
- package/lib/basics.js +144 -0
- package/lib/basics.js.flow +124 -0
- package/lib/basics.mjs +120 -0
- package/lib/booleans.d.ts +16 -0
- package/lib/booleans.js +35 -0
- package/lib/booleans.js.flow +22 -0
- package/lib/booleans.mjs +25 -0
- package/lib/dates.d.ts +15 -0
- package/lib/dates.js +44 -0
- package/lib/dates.js.flow +40 -0
- package/lib/dates.mjs +34 -0
- package/lib/json.d.ts +35 -0
- package/lib/json.js +55 -0
- package/lib/json.js.flow +50 -0
- package/lib/json.mjs +40 -0
- package/lib/numbers.d.ts +31 -0
- package/lib/numbers.js +51 -0
- package/lib/numbers.js.flow +48 -0
- package/lib/numbers.mjs +41 -0
- package/lib/objects.d.ts +75 -0
- package/lib/objects.js +240 -0
- package/lib/objects.js.flow +246 -0
- package/lib/objects.mjs +223 -0
- package/lib/strings.d.ts +56 -0
- package/lib/strings.js +101 -0
- package/lib/strings.js.flow +90 -0
- package/lib/strings.mjs +82 -0
- package/lib/unions.d.ts +55 -0
- package/lib/unions.js +160 -0
- package/lib/unions.js.flow +155 -0
- package/lib/unions.mjs +146 -0
- package/lib/utilities.d.ts +34 -0
- package/lib/utilities.js +75 -0
- package/lib/utilities.js.flow +65 -0
- package/lib/utilities.mjs +60 -0
- package/package.json +79 -29
- package/result.d.ts +16 -0
- package/result.js +34 -0
- package/result.js.flow +26 -0
- package/result.mjs +27 -0
- package/cjs/_guard.js +0 -26
- package/cjs/_guard.js.flow +0 -20
- package/cjs/_types.js +0 -1
- package/cjs/_types.js.flow +0 -20
- package/cjs/format/index.js +0 -12
- package/cjs/format/index.js.flow +0 -4
- package/cjs/format/short.js +0 -10
- package/cjs/format/short.js.flow +0 -8
- package/cjs/index.js +0 -120
- package/cjs/index.js.flow +0 -63
- package/cjs/result.js +0 -172
- package/cjs/result.js.flow +0 -166
- package/cjs/stdlib/array.js +0 -108
- package/cjs/stdlib/array.js.flow +0 -103
- package/cjs/stdlib/boolean.js +0 -44
- package/cjs/stdlib/boolean.js.flow +0 -29
- package/cjs/stdlib/composition.js +0 -56
- package/cjs/stdlib/composition.js.flow +0 -43
- package/cjs/stdlib/constants.js +0 -69
- package/cjs/stdlib/constants.js.flow +0 -46
- package/cjs/stdlib/date.js +0 -46
- package/cjs/stdlib/date.js.flow +0 -40
- package/cjs/stdlib/describe.js +0 -26
- package/cjs/stdlib/describe.js.flow +0 -17
- package/cjs/stdlib/dispatch.js +0 -62
- package/cjs/stdlib/dispatch.js.flow +0 -58
- package/cjs/stdlib/either.js +0 -117
- package/cjs/stdlib/either.js.flow +0 -151
- package/cjs/stdlib/fail.js +0 -21
- package/cjs/stdlib/fail.js.flow +0 -12
- package/cjs/stdlib/instanceOf.js +0 -19
- package/cjs/stdlib/instanceOf.js.flow +0 -20
- package/cjs/stdlib/json.js +0 -31
- package/cjs/stdlib/json.js.flow +0 -28
- package/cjs/stdlib/lazy.js +0 -16
- package/cjs/stdlib/lazy.js.flow +0 -15
- package/cjs/stdlib/mapping.js +0 -67
- package/cjs/stdlib/mapping.js.flow +0 -54
- package/cjs/stdlib/number.js +0 -40
- package/cjs/stdlib/number.js.flow +0 -34
- package/cjs/stdlib/object.js +0 -194
- package/cjs/stdlib/object.js.flow +0 -203
- package/cjs/stdlib/optional.js +0 -54
- package/cjs/stdlib/optional.js.flow +0 -41
- package/cjs/stdlib/string.js +0 -98
- package/cjs/stdlib/string.js.flow +0 -82
- package/cjs/stdlib/tuple.js +0 -173
- package/cjs/stdlib/tuple.js.flow +0 -220
- package/es/_guard.js +0 -15
- package/es/_types.js +0 -0
- package/es/format/index.js +0 -2
- package/es/format/short.js +0 -4
- package/es/index.js +0 -37
- package/es/result.js +0 -139
- package/es/stdlib/array.js +0 -91
- package/es/stdlib/boolean.js +0 -28
- package/es/stdlib/composition.js +0 -42
- package/es/stdlib/constants.js +0 -46
- package/es/stdlib/date.js +0 -28
- package/es/stdlib/describe.js +0 -16
- package/es/stdlib/dispatch.js +0 -51
- package/es/stdlib/either.js +0 -90
- package/es/stdlib/fail.js +0 -11
- package/es/stdlib/instanceOf.js +0 -8
- package/es/stdlib/json.js +0 -15
- package/es/stdlib/lazy.js +0 -11
- package/es/stdlib/mapping.js +0 -54
- package/es/stdlib/number.js +0 -25
- package/es/stdlib/object.js +0 -175
- package/es/stdlib/optional.js +0 -38
- package/es/stdlib/string.js +0 -76
- package/es/stdlib/tuple.js +0 -155
- package/ts/_guard.d.ts +0 -7
- package/ts/_types.d.ts +0 -16
- package/ts/_utils.d.ts +0 -13
- package/ts/array.d.ts +0 -5
- package/ts/boolean.d.ts +0 -5
- package/ts/constants.d.ts +0 -11
- package/ts/date.d.ts +0 -4
- package/ts/describe.d.ts +0 -3
- package/ts/dispatch.d.ts +0 -8
- package/ts/either.d.ts +0 -61
- package/ts/fail.d.ts +0 -3
- package/ts/index.d.ts +0 -42
- package/ts/inline.d.ts +0 -3
- package/ts/instanceOf.d.ts +0 -3
- package/ts/json.d.ts +0 -11
- package/ts/lazy.d.ts +0 -3
- package/ts/mapping.d.ts +0 -4
- package/ts/number.d.ts +0 -6
- package/ts/object.d.ts +0 -33
- package/ts/optional.d.ts +0 -5
- package/ts/result.d.ts +0 -39
- package/ts/short.d.ts +0 -3
- package/ts/string.d.ts +0 -7
- package/ts/tuple.d.ts +0 -30
package/README.md
CHANGED
|
@@ -1,976 +1,139 @@
|
|
|
1
|
-
<img alt="Decoders logo" src="./img/logo@2x.png" width="
|
|
1
|
+
<img alt="Decoders logo" src="./img/logo@2x.png" style="width: 100%; max-width: 830px; max-height: 248px" width="830" height="248" /><br />
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/decoders)
|
|
4
4
|
[](https://github.com/nvie/decoders/actions)
|
|
5
|
-
[](https://coveralls.io/github/nvie/decoders?branch=main)
|
|
6
6
|
[](https://bundlephobia.com/result?p=decoders)
|
|
7
7
|
|
|
8
|
-
Elegant and battle-tested validation library for type-safe input data for
|
|
9
|
-
|
|
8
|
+
Elegant and battle-tested validation library for type-safe input data for
|
|
9
|
+
[TypeScript](https://www.typescriptlang.org/) and [Flow](https://flow.org/).
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Motivation
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Data entering your application from the outside world should not be trusted without
|
|
14
|
+
validation and often is of the `any` type, effectively disabling your type checker around
|
|
15
|
+
input values. It's an industry good practice to validate your expectations right at your
|
|
16
|
+
program's boundaries. This has two benefits: (1) your inputs are getting validated, and
|
|
17
|
+
(2) you can now statically know for sure the shape of the incoming data. **Decoders help
|
|
18
|
+
solve both of these problems at once.**
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
that any data coming from outside your program’s boundaries is essentially untyped and
|
|
17
|
-
unsafe. "Decoders" can help to validate and enforce the correct shape of that data.
|
|
18
|
-
|
|
19
|
-
For example, imagine your app expects a list of points in an incoming HTTP request:
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
{
|
|
23
|
-
points: [
|
|
24
|
-
{ x: 1, y: 2 },
|
|
25
|
-
{ x: 3, y: 4 },
|
|
26
|
-
],
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
In order to decode this, you'll have to tell Flow about the expected structure, and use
|
|
31
|
-
the decoders to validate at runtime that the free-form data will be in the expected shape.
|
|
32
|
-
|
|
33
|
-
```javascript
|
|
34
|
-
type Point = { x: number, y: number };
|
|
35
|
-
|
|
36
|
-
type Payload = {
|
|
37
|
-
points: Array<Point>,
|
|
38
|
-
};
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Here's a decoder that will work for this type:
|
|
42
|
-
|
|
43
|
-
```javascript
|
|
44
|
-
import { array, guard, number, object } from 'decoders';
|
|
45
|
-
|
|
46
|
-
const point = object({
|
|
47
|
-
x: number,
|
|
48
|
-
y: number,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const payload = object({
|
|
52
|
-
points: array(point),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const payloadGuard = guard(payload);
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
And then, you can use it to decode values:
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
>>> payloadGuard(1) // throws!
|
|
62
|
-
>>> payloadGuard('foo') // throws!
|
|
63
|
-
>>> payloadGuard({ // OK!
|
|
64
|
-
... points: [
|
|
65
|
-
... { x: 1, y: 2 },
|
|
66
|
-
... { x: 3, y: 4 },
|
|
67
|
-
... ],
|
|
68
|
-
... })
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## API
|
|
72
|
-
|
|
73
|
-
The decoders package consists of a few building blocks:
|
|
74
|
-
|
|
75
|
-
- [Primitives](#primitives)
|
|
76
|
-
- [Compositions](#compositions)
|
|
77
|
-
- [Building custom decoders](#building-custom-decoders)
|
|
78
|
-
|
|
79
|
-
### Primitives
|
|
80
|
-
|
|
81
|
-
<a name="number" href="#number">#</a> <b>number</b>: <i>Decoder<number></i>
|
|
82
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/number.js 'Source')
|
|
83
|
-
|
|
84
|
-
Returns a decoder capable of decoding finite (!) numbers (integer or float values). This
|
|
85
|
-
means that values like `NaN`, or positive and negative `Infinity` are not considered valid
|
|
86
|
-
numbers.
|
|
87
|
-
|
|
88
|
-
```javascript
|
|
89
|
-
const mydecoder = guard(number);
|
|
90
|
-
mydecoder(123) === 123;
|
|
91
|
-
mydecoder(-3.14) === -3.14;
|
|
92
|
-
mydecoder(NaN); // DecodeError
|
|
93
|
-
mydecoder('not a number'); // DecodeError
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
<a name="integer" href="#integer">#</a> <b>integer</b>: <i>Decoder<integer></i>
|
|
99
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/number.js 'Source')
|
|
100
|
-
|
|
101
|
-
Like `number`, but only decodes values that are whole numbers.
|
|
102
|
-
|
|
103
|
-
```javascript
|
|
104
|
-
const mydecoder = guard(integer);
|
|
105
|
-
mydecoder(123) === 123;
|
|
106
|
-
mydecoder(-3.14); // DecodeError: floats aren't valid integers
|
|
107
|
-
mydecoder(NaN); // DecodeError
|
|
108
|
-
mydecoder('not a integer'); // DecodeError
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
<a name="string" href="#string">#</a> <b>string</b>: <i>Decoder<string></i>
|
|
114
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/string.js 'Source')
|
|
115
|
-
|
|
116
|
-
Returns a decoder capable of decoding string values.
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
const mydecoder = guard(string);
|
|
120
|
-
mydecoder('hello world') === 'hello world';
|
|
121
|
-
mydecoder(123); // DecodeError
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
<a name="nonEmptyString" href="#nonEmptyString">#</a> <b>nonEmptyString</b>:
|
|
127
|
-
<i>Decoder<string></i>
|
|
128
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/string.js 'Source')
|
|
129
|
-
|
|
130
|
-
Like `string`, but will fail on inputs with only whitespace (or the empty string).
|
|
131
|
-
|
|
132
|
-
```javascript
|
|
133
|
-
const mydecoder = guard(nonEmptyString);
|
|
134
|
-
mydecoder('hello world') === 'hello world';
|
|
135
|
-
mydecoder(123); // DecodeError
|
|
136
|
-
mydecoder(' '); // DecodeError
|
|
137
|
-
mydecoder(''); // DecodeError
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
<a name="regex" href="#regex">#</a> <b>regex</b>(): <i>Decoder<string></i>
|
|
143
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/string.js 'Source')
|
|
144
|
-
|
|
145
|
-
Returns a decoder capable of decoding string values that match the given regular
|
|
146
|
-
expression.
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
const mydecoder = guard(regex(/^[0-9]+$/));
|
|
150
|
-
mydecoder('12345') === '12345';
|
|
151
|
-
mydecoder('foo'); // DecodeError
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
<a name="email" href="#email">#</a> <b>email</b>: <i>Decoder<string></i>
|
|
157
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/string.js 'Source')
|
|
158
|
-
|
|
159
|
-
Returns a decoder capable of decoding email addresses (using a regular expression).
|
|
160
|
-
|
|
161
|
-
```javascript
|
|
162
|
-
const mydecoder = guard(email);
|
|
163
|
-
mydecoder('foo'); // DecodeError
|
|
164
|
-
mydecoder('alice@acme.org') === 'alice@acme.org';
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
<a name="boolean" href="#boolean">#</a> <b>boolean</b>: <i>Decoder<boolean></i>
|
|
170
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/boolean.js 'Source')
|
|
171
|
-
|
|
172
|
-
Returns a decoder capable of decoding boolean values.
|
|
173
|
-
|
|
174
|
-
```javascript
|
|
175
|
-
const mydecoder = guard(boolean);
|
|
176
|
-
mydecoder(false) === false;
|
|
177
|
-
mydecoder(true) === true;
|
|
178
|
-
mydecoder(undefined); // DecodeError
|
|
179
|
-
mydecoder('hello world'); // DecodeError
|
|
180
|
-
mydecoder(123); // DecodeError
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
<a name="truthy" href="#truthy">#</a> <b>truthy</b>: <i>Decoder<boolean></i>
|
|
186
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/boolean.js 'Source')
|
|
187
|
-
|
|
188
|
-
Returns a decoder capable of decoding any input value to its "truthy value".
|
|
189
|
-
|
|
190
|
-
```javascript
|
|
191
|
-
const mydecoder = guard(truthy);
|
|
192
|
-
mydecoder(false) === false;
|
|
193
|
-
mydecoder(true) === true;
|
|
194
|
-
mydecoder(undefined) === false;
|
|
195
|
-
mydecoder('hello world') === true;
|
|
196
|
-
mydecoder('false') === true;
|
|
197
|
-
mydecoder(0) === false;
|
|
198
|
-
mydecoder(1) === true;
|
|
199
|
-
mydecoder(null) === false;
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
---
|
|
203
|
-
|
|
204
|
-
<a name="numericBoolean" href="#numericBoolean">#</a> <b>numericBoolean</b>:
|
|
205
|
-
<i>Decoder<boolean></i>
|
|
206
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/boolean.js 'Source')
|
|
207
|
-
|
|
208
|
-
Returns a decoder capable of decoding numbers to their boolean representation.
|
|
209
|
-
|
|
210
|
-
```javascript
|
|
211
|
-
const mydecoder = guard(numericBoolean);
|
|
212
|
-
mydecoder(-1) === true;
|
|
213
|
-
mydecoder(0) === false;
|
|
214
|
-
mydecoder(123) === true;
|
|
215
|
-
mydecoder(false); // DecodeError
|
|
216
|
-
mydecoder(true); // DecodeError
|
|
217
|
-
mydecoder(undefined); // DecodeError
|
|
218
|
-
mydecoder('hello'); // DecodeError
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
<a name="date" href="#date">#</a> <b>date</b>: <i>Decoder<Date></i>
|
|
224
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/date.js 'Source')
|
|
225
|
-
|
|
226
|
-
Returns a decoder capable of decoding
|
|
227
|
-
[Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
|
|
228
|
-
values.
|
|
229
|
-
|
|
230
|
-
```javascript
|
|
231
|
-
const now = new Date();
|
|
232
|
-
const mydecoder = guard(date);
|
|
233
|
-
mydecoder(now) === now;
|
|
234
|
-
mydecoder(123); // DecodeError
|
|
235
|
-
mydecoder('hello'); // DecodeError
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
<a name="iso8601" href="#iso8601">#</a> <b>iso8601</b>: <i>Decoder<Date></i>
|
|
241
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/date.js 'Source')
|
|
242
|
-
|
|
243
|
-
Returns a decoder capable of decoding
|
|
244
|
-
[ISO8601](https://en.wikipedia.org/wiki/ISO_8601)-formatted date strings. This is very
|
|
245
|
-
useful for working with dates in APIs: serialize them as `.toISOString()` when sending,
|
|
246
|
-
decode them as `iso8601` when receiving.
|
|
247
|
-
|
|
248
|
-
**NOTE:** This decoder reads a _string_, but returns a _Date_ instance.
|
|
249
|
-
|
|
250
|
-
```javascript
|
|
251
|
-
const mydecoder = guard(iso8601);
|
|
252
|
-
mydecoder('2020-06-01T12:00:00Z'); // new Date('2020-06-01T12:00:00Z')
|
|
253
|
-
mydecoder('2020-06-01'); // DecodeError
|
|
254
|
-
mydecoder('hello'); // DecodeError
|
|
255
|
-
mydecoder(123); // DecodeError
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
<a name="null_" href="#null_">#</a> <b>null\_</b>: <i>Decoder<null></i>
|
|
261
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')
|
|
262
|
-
|
|
263
|
-
Returns a decoder capable of decoding the constant value `null`.
|
|
264
|
-
|
|
265
|
-
```javascript
|
|
266
|
-
const mydecoder = guard(null_);
|
|
267
|
-
mydecoder(null) === null;
|
|
268
|
-
mydecoder(false); // DecodeError
|
|
269
|
-
mydecoder(undefined); // DecodeError
|
|
270
|
-
mydecoder('hello world'); // DecodeError
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
<a name="undefined_" href="#undefined_">#</a> <b>undefined\_</b>:
|
|
276
|
-
<i>Decoder<void></i>
|
|
277
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')
|
|
278
|
-
|
|
279
|
-
Returns a decoder capable of decoding the constant value `undefined`.
|
|
280
|
-
|
|
281
|
-
```javascript
|
|
282
|
-
const mydecoder = guard(undefined_);
|
|
283
|
-
mydecoder(undefined) === undefined;
|
|
284
|
-
mydecoder(null); // DecodeError
|
|
285
|
-
mydecoder(false); // DecodeError
|
|
286
|
-
mydecoder('hello world'); // DecodeError
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
<a name="constant" href="#constant">#</a> <b>constant</b><i><T></i>(value: T):
|
|
292
|
-
<i>Decoder<T></i>
|
|
293
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')
|
|
294
|
-
|
|
295
|
-
Returns a decoder capable of decoding just the given constant value.
|
|
296
|
-
|
|
297
|
-
For Flow, use this syntax:
|
|
298
|
-
|
|
299
|
-
```javascript
|
|
300
|
-
constant(('something': 'something'));
|
|
301
|
-
constant((42: 42));
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
Example:
|
|
20
|
+
## Example
|
|
305
21
|
|
|
306
22
|
```typescript
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')
|
|
319
|
-
|
|
320
|
-
Returns a decoder that will always return the provided value **without looking at the
|
|
321
|
-
input**. This is useful to manually add extra fields.
|
|
322
|
-
|
|
323
|
-
```javascript
|
|
324
|
-
const mydecoder = guard(hardcoded(2.1));
|
|
325
|
-
mydecoder('hello') === 2.1;
|
|
326
|
-
mydecoder(false) === 2.1;
|
|
327
|
-
mydecoder(undefined) === 2.1;
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
<a name="fail" href="#fail">#</a> <b>fail</b>(): <i>Decoder<empty></i>
|
|
333
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/fail.js 'Source')
|
|
334
|
-
|
|
335
|
-
Returns a decoder that will always fail with the given error messages, no matter what the
|
|
336
|
-
input. May be useful for explicitly disallowing keys, or for testing purposes.
|
|
337
|
-
|
|
338
|
-
```javascript
|
|
339
|
-
const mydecoder = guard(object({ a: string, b: optional(fail('Key b has been removed')) })));
|
|
340
|
-
mydecoder({ a: 'foo' }) === { a: 'foo' }
|
|
341
|
-
mydecoder({ a: 'foo', c: 'bar' }) === { a: 'foo' }
|
|
342
|
-
mydecoder({ a: 'foo', b: 'bar' }) // DecodeError
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
---
|
|
346
|
-
|
|
347
|
-
<a name="mixed" href="#mixed">#</a> <b>mixed</b>: <i>Decoder<mixed></i>
|
|
348
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')<br />
|
|
349
|
-
<a name="unknown" href="#unknown">#</a> <b>unknown</b>: <i>Decoder<unknown></i>
|
|
350
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')
|
|
351
|
-
|
|
352
|
-
Returns a decoder that will simply pass through any input value, never fails. This
|
|
353
|
-
effectively returns a `Decoder<mixed>`, which is not that useful. **Use sparingly.**
|
|
354
|
-
|
|
355
|
-
Same as `unknown` in TypeScript.
|
|
356
|
-
|
|
357
|
-
```javascript
|
|
358
|
-
const mydecoder = guard(mixed);
|
|
359
|
-
mydecoder('hello') === 'hello';
|
|
360
|
-
mydecoder(false) === false;
|
|
361
|
-
mydecoder(undefined) === undefined;
|
|
362
|
-
mydecoder([1, 2]) === [1, 2];
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### Compositions
|
|
366
|
-
|
|
367
|
-
Composite decoders are "higher order" decoders that can build new decoders from existing
|
|
368
|
-
decoders that can already decode a "subtype". Examples are: if you already have a decoder
|
|
369
|
-
for a `Point` (= `Decoder<Point>`), then you can use `array()` to automatically build a
|
|
370
|
-
decoder for arrays of points: `array(pointDecoder)`, which will be of type
|
|
371
|
-
`Decoder<Array<Point>>`.
|
|
372
|
-
|
|
373
|
-
<a name="optional" href="#optional">#</a>
|
|
374
|
-
<b>optional</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<T | void></i>
|
|
375
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/optional.js 'Source')
|
|
376
|
-
|
|
377
|
-
Returns a decoder capable of decoding **either a value of type <i>T</i>, or `undefined`**,
|
|
378
|
-
provided that you already have a decoder for <i>T</i>.
|
|
379
|
-
|
|
380
|
-
```javascript
|
|
381
|
-
const mydecoder = guard(optional(string));
|
|
382
|
-
mydecoder('hello') === 'hello';
|
|
383
|
-
mydecoder(undefined) === undefined;
|
|
384
|
-
mydecoder(null); // DecodeError
|
|
385
|
-
mydecoder(0); // DecodeError
|
|
386
|
-
mydecoder(42); // DecodeError
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
A typical case where `optional` is useful is in decoding objects with optional fields:
|
|
23
|
+
import { array, iso8601, number, object, optional, string } from 'decoders';
|
|
24
|
+
|
|
25
|
+
//
|
|
26
|
+
// Incoming data at runtime
|
|
27
|
+
//
|
|
28
|
+
const externalData = {
|
|
29
|
+
id: 123,
|
|
30
|
+
name: 'Alison Roberts',
|
|
31
|
+
createdAt: '1994-01-11T12:26:37.024Z',
|
|
32
|
+
tags: ['foo', 'bar'],
|
|
33
|
+
};
|
|
390
34
|
|
|
391
|
-
|
|
392
|
-
|
|
35
|
+
//
|
|
36
|
+
// Write the decoder (= what you expect the data to look like)
|
|
37
|
+
//
|
|
38
|
+
const userDecoder = object({
|
|
393
39
|
id: number,
|
|
394
40
|
name: string,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
Which will decode to type:
|
|
400
|
-
|
|
401
|
-
```javascript
|
|
402
|
-
{
|
|
403
|
-
id: number,
|
|
404
|
-
name: string,
|
|
405
|
-
address?: string,
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
---
|
|
410
|
-
|
|
411
|
-
<a name="nullable" href="#nullable">#</a>
|
|
412
|
-
<b>nullable</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<T | null></i>
|
|
413
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/optional.js 'Source')
|
|
414
|
-
|
|
415
|
-
Returns a decoder capable of decoding **either a value of type <i>T</i>, or `null`**,
|
|
416
|
-
provided that you already have a decoder for <i>T</i>.
|
|
417
|
-
|
|
418
|
-
```javascript
|
|
419
|
-
const mydecoder = guard(nullable(string));
|
|
420
|
-
mydecoder('hello') === 'hello';
|
|
421
|
-
mydecoder(null) === null;
|
|
422
|
-
mydecoder(undefined); // DecodeError
|
|
423
|
-
mydecoder(0); // DecodeError
|
|
424
|
-
mydecoder(42); // DecodeError
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
---
|
|
428
|
-
|
|
429
|
-
<a name="maybe" href="#maybe">#</a> <b>maybe</b><i><T></i>(<i>Decoder<T></i>):
|
|
430
|
-
<i>Decoder<?T></i>
|
|
431
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/optional.js 'Source')
|
|
432
|
-
|
|
433
|
-
Returns a decoder capable of decoding **either a value of type <i>T</i>, or `null`, or
|
|
434
|
-
`undefined`**, provided that you already have a decoder for <i>T</i>.
|
|
435
|
-
|
|
436
|
-
```javascript
|
|
437
|
-
const mydecoder = guard(maybe(string));
|
|
438
|
-
mydecoder('hello') === 'hello';
|
|
439
|
-
mydecoder(null) === null;
|
|
440
|
-
mydecoder(undefined) === undefined;
|
|
441
|
-
mydecoder(0); // DecodeError
|
|
442
|
-
mydecoder(42); // DecodeError
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
<a name="array" href="#array">#</a> <b>array</b><i><T></i>(<i>Decoder<T></i>):
|
|
448
|
-
<i>Decoder<Array<T>></i>
|
|
449
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/array.js 'Source')
|
|
450
|
-
|
|
451
|
-
Returns a decoder capable of decoding **an array of <i>T</i>'s**, provided that you
|
|
452
|
-
already have a decoder for <i>T</i>.
|
|
453
|
-
|
|
454
|
-
```javascript
|
|
455
|
-
const mydecoder = guard(array(string));
|
|
456
|
-
mydecoder(['hello', 'world']) === ['hello', 'world'];
|
|
457
|
-
mydecoder(['hello', 1.2]); // DecodeError
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
---
|
|
461
|
-
|
|
462
|
-
<a name="nonEmptyArray" href="#nonEmptyArray">#</a>
|
|
463
|
-
<b>nonEmptyArray</b><i><T></i>(<i>Decoder<T></i>):
|
|
464
|
-
<i>Decoder<Array<T>></i>
|
|
465
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/array.js 'Source')
|
|
466
|
-
|
|
467
|
-
Like `array()`, but will fail on inputs with 0 elements.
|
|
468
|
-
|
|
469
|
-
```javascript
|
|
470
|
-
const mydecoder = guard(nonEmptyArray(string));
|
|
471
|
-
mydecoder(['hello', 'world']) === ['hello', 'world'];
|
|
472
|
-
mydecoder(['hello', 1.2]); // DecodeError
|
|
473
|
-
mydecoder([]); // DecodeError
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
---
|
|
477
|
-
|
|
478
|
-
<a name="tuple1" href="#tuple1">#</a>
|
|
479
|
-
<b>tuple1</b><i><T1></i>(<i>Decoder<T1></i>): <i>Decoder<[T1]></i>
|
|
480
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
481
|
-
<a name="tuple2" href="#tuple2">#</a> <b>tuple2</b><i><T1,
|
|
482
|
-
T2></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>): <i>Decoder<[T1,
|
|
483
|
-
T2]></i>
|
|
484
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
485
|
-
<a name="tuple3" href="#tuple3">#</a> <b>tuple3</b><i><T1, T2,
|
|
486
|
-
T3></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>):
|
|
487
|
-
<i>Decoder<[T1, T2, T3]></i>
|
|
488
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
489
|
-
<a name="tuple4" href="#tuple4">#</a> <b>tuple4</b><i><T1, T2, T3,
|
|
490
|
-
T4></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
491
|
-
<i>Decoder<T4></i>): <i>Decoder<[T1, T2, T3, T4]></i>
|
|
492
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
493
|
-
<a name="tuple5" href="#tuple5">#</a> <b>tuple5</b><i><T1, T2, T3, T4,
|
|
494
|
-
T5></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
495
|
-
<i>Decoder<T3></i>, <i>Decoder<T4></i>, <i>Decoder<T5></i>):
|
|
496
|
-
<i>Decoder<[T1, T2, T3, T4, T5]></i>
|
|
497
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
|
|
498
|
-
<a name="tuple6" href="#tuple6">#</a> <b>tuple6</b><i><T1, T2, T3, T4, T5,
|
|
499
|
-
T6></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>,
|
|
500
|
-
<i>Decoder<T4></i>, <i>Decoder<T5></i>, <i>Decoder<T6></i>):
|
|
501
|
-
<i>Decoder<[T1, T2, T3, T4, T5, T6]></i>
|
|
502
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')
|
|
503
|
-
|
|
504
|
-
Returns a decoder capable of decoding **a 2-tuple of <i>(T1, T2)</i>'s**, provided that
|
|
505
|
-
you already have a decoder for <i>T1</i> and <i>T2</i>. A tuple is like an Array, but the
|
|
506
|
-
number of items in the array is fixed (two) and their types don't have to be homogeneous.
|
|
507
|
-
|
|
508
|
-
```javascript
|
|
509
|
-
const mydecoder = guard(tuple2(string, number));
|
|
510
|
-
mydecoder(['hello', 1.2]) === ['hello', 1.2];
|
|
511
|
-
mydecoder(['hello', 'world']); // DecodeError
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
---
|
|
515
|
-
|
|
516
|
-
<a name="object" href="#object">#</a> <b>object</b><i><O: { [field: string]:
|
|
517
|
-
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
518
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/object.js 'Source')
|
|
519
|
-
|
|
520
|
-
Returns a decoder capable of decoding **objects of the given shape** corresponding
|
|
521
|
-
decoders, provided that you already have decoders for all values in the mapping.
|
|
522
|
-
|
|
523
|
-
```javascript
|
|
524
|
-
const mydecoder = guard(
|
|
525
|
-
object({
|
|
526
|
-
x: number,
|
|
527
|
-
y: number,
|
|
528
|
-
})
|
|
529
|
-
);
|
|
530
|
-
mydecoder({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
531
|
-
mydecoder({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2 }; // ⚠️
|
|
532
|
-
mydecoder({ x: 1 }); // DecodeError (Missing key: "y")
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
For more information, see also
|
|
536
|
-
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
537
|
-
|
|
538
|
-
---
|
|
539
|
-
|
|
540
|
-
<a name="exact" href="#exact">#</a> <b>exact</b><i><O: { [field: string]:
|
|
541
|
-
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
542
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/object.js 'Source')
|
|
543
|
-
|
|
544
|
-
Like `object()`, but will fail if there are superfluous keys in the input data.
|
|
545
|
-
|
|
546
|
-
```javascript
|
|
547
|
-
const mydecoder = guard(
|
|
548
|
-
exact({
|
|
549
|
-
x: number,
|
|
550
|
-
y: number,
|
|
551
|
-
})
|
|
552
|
-
);
|
|
553
|
-
mydecoder({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
554
|
-
mydecoder({ x: 1, y: 2, z: 3 }); // DecodeError (Superfluous keys: "z")
|
|
555
|
-
mydecoder({ x: 1 }); // DecodeError (Missing key: "y")
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
For more information, see also
|
|
559
|
-
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
560
|
-
|
|
561
|
-
---
|
|
562
|
-
|
|
563
|
-
<a name="inexact" href="#inexact">#</a> <b>inexact</b><i><O: { [field: string]:
|
|
564
|
-
Decoder<any> }></i>(mapping: O): <i>Decoder<{ ... }></i>
|
|
565
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/object.js 'Source')
|
|
566
|
-
|
|
567
|
-
Like `object()`, but will retain any extra properties on the input type unvalidated that
|
|
568
|
-
are not part of the decoder definition.
|
|
569
|
-
|
|
570
|
-
```javascript
|
|
571
|
-
const mydecoder = guard(
|
|
572
|
-
inexact({
|
|
573
|
-
x: number,
|
|
574
|
-
})
|
|
575
|
-
);
|
|
576
|
-
|
|
577
|
-
mydecoder({ x: 1, y: 2 }) === { x: 1, y: 2 };
|
|
578
|
-
mydecoder({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2, z: 3 };
|
|
579
|
-
mydecoder({ x: 1 }); // DecodeError (Missing key: "y")
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
For more information, see also
|
|
583
|
-
[The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
|
|
584
|
-
|
|
585
|
-
---
|
|
586
|
-
|
|
587
|
-
<a name="mapping" href="#mapping">#</a>
|
|
588
|
-
<b>mapping</b><i><T></i>(<i>Decoder<T></i>): <i>Decoder<Map<string,
|
|
589
|
-
T>></i>
|
|
590
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/mapping.js 'Source')
|
|
591
|
-
|
|
592
|
-
Returns a decoder capable of decoding **Map instances of strings-to-T's** , provided that
|
|
593
|
-
you already have a decoder for <i>T</i>.
|
|
594
|
-
|
|
595
|
-
The main difference between `object()` and `mapping()` is that you'd typically use
|
|
596
|
-
`object()` if this is a record-like object, where you know all the field names and the
|
|
597
|
-
values are heterogeneous. Whereas with Mappings the keys are typically unknown and the
|
|
598
|
-
values homogeneous.
|
|
599
|
-
|
|
600
|
-
```javascript
|
|
601
|
-
const mydecoder = guard(mapping(person)); // Assume you have a "person" decoder already
|
|
602
|
-
mydecoder({
|
|
603
|
-
'1': { name: 'Alice' },
|
|
604
|
-
'2': { name: 'Bob' },
|
|
605
|
-
'3': { name: 'Charlie' },
|
|
606
|
-
}) ===
|
|
607
|
-
Map([
|
|
608
|
-
['1', { name: 'Alice' }],
|
|
609
|
-
['2', { name: 'Bob' }],
|
|
610
|
-
['3', { name: 'Charlie' }],
|
|
611
|
-
]);
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
---
|
|
615
|
-
|
|
616
|
-
<a name="dict" href="#dict">#</a> <b>dict</b><i><T></i>(<i>Decoder<T></i>):
|
|
617
|
-
<i>Decoder<{ [string]: <T>}></i>
|
|
618
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/mapping.js 'Source')
|
|
619
|
-
|
|
620
|
-
Like `mapping()`, but returns an object instead of a `Map` instance.
|
|
621
|
-
|
|
622
|
-
```javascript
|
|
623
|
-
const mydecoder = guard(dict(person)); // Assume you have a "person" decoder already
|
|
624
|
-
mydecoder({
|
|
625
|
-
'1': { name: 'Alice' },
|
|
626
|
-
'2': { name: 'Bob' },
|
|
627
|
-
'3': { name: 'Charlie' },
|
|
628
|
-
});
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
Would equal:
|
|
632
|
-
|
|
633
|
-
```javascript
|
|
634
|
-
{
|
|
635
|
-
"1": { name: "Alice" },
|
|
636
|
-
"2": { name: "Bob" },
|
|
637
|
-
"3": { name: "Charlie" },
|
|
638
|
-
}
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
---
|
|
642
|
-
|
|
643
|
-
<a name="json" href="#json">#</a> <b>json</b>: <i>Decoder<JSONValue></i>
|
|
644
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/json.js 'Source')
|
|
645
|
-
|
|
646
|
-
Returns a decoder capable of decoding **any valid JSON value**:
|
|
647
|
-
|
|
648
|
-
- `null`
|
|
649
|
-
- `string`
|
|
650
|
-
- `number`
|
|
651
|
-
- `boolean`
|
|
652
|
-
- `{ [string]: JSONValue }`
|
|
653
|
-
- `Array<JSONValue>`
|
|
654
|
-
|
|
655
|
-
```javascript
|
|
656
|
-
const mydecoder = guard(json);
|
|
657
|
-
mydecoder({
|
|
658
|
-
name: 'Amir',
|
|
659
|
-
age: 27,
|
|
660
|
-
admin: true,
|
|
661
|
-
image: null,
|
|
662
|
-
tags: ['vip', 'staff'],
|
|
663
|
-
});
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
Any value returned by `JSON.parse()` should decode without failure.
|
|
667
|
-
|
|
668
|
-
---
|
|
669
|
-
|
|
670
|
-
<a name="jsonObject" href="#jsonObject">#</a> <b>jsonObject</b>:
|
|
671
|
-
<i>Decoder<JSONObject></i>
|
|
672
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/json.js 'Source')
|
|
673
|
-
|
|
674
|
-
Like `json`, but will only decode when the JSON value is an object.
|
|
675
|
-
|
|
676
|
-
```javascript
|
|
677
|
-
const mydecoder = guard(json);
|
|
678
|
-
mydecoder({}); // OK
|
|
679
|
-
mydecoder({ name: 'Amir' }); // OK
|
|
680
|
-
|
|
681
|
-
// Error: the following values are valid JSON values, but not Objects
|
|
682
|
-
mydecoder([]); // Error
|
|
683
|
-
mydecoder([{ name: 'Alice' }, { name: 'Bob' }]); // Error
|
|
684
|
-
mydecoder('hello'); // Error
|
|
685
|
-
mydecoder(null); // Error
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
---
|
|
689
|
-
|
|
690
|
-
<a name="jsonArray" href="#jsonArray">#</a> <b>jsonArray</b>:
|
|
691
|
-
<i>Decoder<JSONArray></i>
|
|
692
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/json.js 'Source')
|
|
693
|
-
|
|
694
|
-
Like `json`, but will only decode when the JSON value is an array.
|
|
695
|
-
|
|
696
|
-
```javascript
|
|
697
|
-
const mydecoder = guard(json);
|
|
698
|
-
mydecoder([]); // OK
|
|
699
|
-
mydecoder([{ name: 'Amir' }]); // OK
|
|
700
|
-
|
|
701
|
-
// Error: the following values are valid JSON values, but not Objects
|
|
702
|
-
mydecoder({}); // Error
|
|
703
|
-
mydecoder({ name: 'Alice' }); // Error
|
|
704
|
-
mydecoder('hello'); // Error
|
|
705
|
-
mydecoder(null); // Error
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
---
|
|
709
|
-
|
|
710
|
-
<a name="either" href="#either">#</a> <b>either</b><i><T1,
|
|
711
|
-
T2></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>): <i>Decoder<T1 |
|
|
712
|
-
T2></i><br />
|
|
713
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
|
|
714
|
-
<a name="either2" href="#either2">#</a> <b>either2</b><i><T1,
|
|
715
|
-
T2></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>): <i>Decoder<T1 |
|
|
716
|
-
T2></i><br />
|
|
717
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
|
|
718
|
-
<a name="either3" href="#either3">#</a> <b>either3</b><i><T1, T2,
|
|
719
|
-
T3></i>(<i>Decoder<T1></i>, <i>Decoder<T2></i>, <i>Decoder<T3></i>):
|
|
720
|
-
<i>Decoder<T1 | T2 | T3></i>
|
|
721
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br /> ...
|
|
722
|
-
|
|
723
|
-
Returns a decoder capable of decoding **either one of <i>T1</i> or <i>T2</i>**, provided
|
|
724
|
-
that you already have decoders for <i>T1</i> and <i>T2</i>. Eithers exist for arities up
|
|
725
|
-
until 9 (either, either3, either4, ..., either9).
|
|
726
|
-
|
|
727
|
-
```javascript
|
|
728
|
-
const mydecoder = guard(either(number, string));
|
|
729
|
-
mydecoder('hello world') === 'hello world';
|
|
730
|
-
mydecoder(123) === 123;
|
|
731
|
-
mydecoder(false); // DecodeError
|
|
732
|
-
```
|
|
733
|
-
|
|
734
|
-
---
|
|
735
|
-
|
|
736
|
-
<a name="dispatch" href="#dispatch">#</a> <b>dispatch</b><i><O: { [field: string]:
|
|
737
|
-
(Decoder<T> | Decoder<V> | ...) }></i>(field: string, mapping: O):
|
|
738
|
-
<i>Decoder<T | V | ...></i>
|
|
739
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/dispatch.js 'Source')
|
|
740
|
-
|
|
741
|
-
Like the `either` family, but only for building unions of object types with a common field
|
|
742
|
-
(like a `type` field) that lets you distinguish members.
|
|
743
|
-
|
|
744
|
-
The following two decoders are effectively equivalent:
|
|
745
|
-
|
|
746
|
-
```javascript
|
|
747
|
-
type Rect = {| __type: 'rect', x: number, y: number, width: number, height: number |};
|
|
748
|
-
type Circle = {| __type: 'circle', cx: number, cy: number, r: number |};
|
|
749
|
-
// ^^^^^^
|
|
750
|
-
// Field that defines which decoder to pick
|
|
751
|
-
// vvvvvv
|
|
752
|
-
const shape1: Decoder<Rect | Circle> = dispatch('__type', { rect, circle });
|
|
753
|
-
const shape2: Decoder<Rect | Circle> = either(rect, circle);
|
|
754
|
-
```
|
|
755
|
-
|
|
756
|
-
But using `dispatch()` will typically be more runtime-efficient than using `either()`. The
|
|
757
|
-
reason is that `dispatch()` will first do minimal work to "look ahead" into the `type`
|
|
758
|
-
field here, and based on that value, pick which decoder to invoke. Error messages will
|
|
759
|
-
then also be tailored to the specific decoder.
|
|
760
|
-
|
|
761
|
-
The `either()` version will instead try each decoder in turn until it finds one that
|
|
762
|
-
matches. If none of the alternatives match, it needs to report all errors, which is
|
|
763
|
-
sometimes confusing.
|
|
764
|
-
|
|
765
|
-
---
|
|
766
|
-
|
|
767
|
-
<a name="oneOf" href="#oneOf">#</a> <b>oneOf</b><i><T></i>(<i>Array<T></i>):
|
|
768
|
-
<i>Decoder<T></i>
|
|
769
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
|
|
770
|
-
|
|
771
|
-
Returns a decoder capable of decoding values that are equal (using `===`) to any of the
|
|
772
|
-
given constants. The returned value will always be one of the given constants at runtime.
|
|
773
|
-
|
|
774
|
-
```javascript
|
|
775
|
-
const mydecoder = guard(oneOf(['foo', 'bar', 3]));
|
|
776
|
-
mydecoder('foo') === 'foo';
|
|
777
|
-
mydecoder(3) === 3;
|
|
778
|
-
mydecoder('hello'); // DecodeError
|
|
779
|
-
mydecoder(4); // DecodeError
|
|
780
|
-
mydecoder(false); // DecodeError
|
|
781
|
-
```
|
|
782
|
-
|
|
783
|
-
For example, given an array of strings, like so:
|
|
784
|
-
|
|
785
|
-
```javascript
|
|
786
|
-
oneOf(['foo', 'bar']);
|
|
787
|
-
```
|
|
788
|
-
|
|
789
|
-
TypeScript is capable of inferring the return type as `Decoder<'foo' | 'bar'>`, but in
|
|
790
|
-
Flow it will (unfortunately) be `Decoder<string>`. So in Flow, be sure to explicitly
|
|
791
|
-
annotate the type. Either by doing `oneOf([('foo': 'foo'), ('bar': 'bar')])`, or as
|
|
792
|
-
`oneOf<'foo' | 'bar'>(['foo', 'bar'])`.
|
|
793
|
-
|
|
794
|
-
---
|
|
795
|
-
|
|
796
|
-
<a name="instanceOf" href="#instanceOf">#</a>
|
|
797
|
-
<b>instanceOf</b><i><T></i>(<i>Class<T></i>): <i>Decoder<T></i>
|
|
798
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/instanceOf.js 'Source')<br />
|
|
799
|
-
|
|
800
|
-
Returns a decoder capable of decoding values that are instances of the given class.
|
|
801
|
-
|
|
802
|
-
> **NOTE: Help wanted!** The TypeScript annotation for this decoder needs help! If you
|
|
803
|
-
> know how to express it, please submit a PR. See
|
|
804
|
-
> https://github.com/nvie/decoders/blob/master/src/instanceOf.d.ts
|
|
805
|
-
|
|
806
|
-
```javascript
|
|
807
|
-
const mydecoder = guard(instanceOf(Error));
|
|
808
|
-
const value = new Error('foo');
|
|
809
|
-
mydecoder(value) === value;
|
|
810
|
-
mydecoder('foo'); // DecodeError
|
|
811
|
-
mydecoder(3); // DecodeError
|
|
812
|
-
```
|
|
813
|
-
|
|
814
|
-
---
|
|
815
|
-
|
|
816
|
-
<a name="map" href="#map">#</a> <b>map</b><i><T, V></i>(<i>Decoder<T></i>,
|
|
817
|
-
<i><T></i> => <i><V></i>): <i>Decoder<V></i>
|
|
818
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/utils.js 'Source')<br />
|
|
819
|
-
|
|
820
|
-
Given a decoder and a mapper function, will first decode the value using the given
|
|
821
|
-
decoder, and on success, will call the mapper function **on the decoded value**. If the
|
|
822
|
-
mapper function throws an error, the whole decoder will fail using the error message as
|
|
823
|
-
the failure reason.
|
|
824
|
-
|
|
825
|
-
```javascript
|
|
826
|
-
const upper = map(string, (s) => s.toUpperCase());
|
|
827
|
-
|
|
828
|
-
const mydecoder = guard(upper);
|
|
829
|
-
mydecoder(4); // DecodeError
|
|
830
|
-
mydecoder('foo') === 'FOO';
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
---
|
|
834
|
-
|
|
835
|
-
<a name="compose" href="#compose">#</a> <b>compose</b><i><T,
|
|
836
|
-
V></i>(<i>Decoder<T></i>, <i>Decoder<V, T></i>): <i>Decoder<V></i>
|
|
837
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/utils.js 'Source')<br />
|
|
838
|
-
|
|
839
|
-
Given a decoder for _T_ and another one for _V_, will first decode using _T_, and then
|
|
840
|
-
call the _V_ decoder **on the original value**. This differs from `map()` in that it was
|
|
841
|
-
access to the original value, but may assume the type value is already refined by the
|
|
842
|
-
first decoder.
|
|
843
|
-
|
|
844
|
-
Although the `compose()` function is essentially more low-level and powerful then the
|
|
845
|
-
`map()` function, it's mostly useful in combination with the `predicate()` helper
|
|
846
|
-
function, which allows you to rely on an existing decoder, but add extra checks on the
|
|
847
|
-
specific values that will be allowed at runtime.
|
|
848
|
-
|
|
849
|
-
---
|
|
850
|
-
|
|
851
|
-
<a name="describe" href="#describe">#</a>
|
|
852
|
-
<b>describe</b><i><T></i>(<i>Decoder<T></i>, <i>string</i>):
|
|
853
|
-
<i>Decoder<T></i>
|
|
854
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/describe.js 'Source')<br />
|
|
855
|
-
|
|
856
|
-
Defers to the given decoder, but when a decoding error happens, replace the error message
|
|
857
|
-
with the given one. This can be used to simplify or shorten otherwise long or
|
|
858
|
-
low-level/technical errors.
|
|
859
|
-
|
|
860
|
-
```javascript
|
|
861
|
-
const vowel = describe(
|
|
862
|
-
either5(constant('a'), constant('e'), constant('i'), constant('o'), constant('u')),
|
|
863
|
-
'Must be vowel'
|
|
864
|
-
);
|
|
865
|
-
```
|
|
866
|
-
|
|
867
|
-
---
|
|
868
|
-
|
|
869
|
-
<a name="lazy" href="#lazy">#</a> <b>lazy</b><i><T></i>(() =>
|
|
870
|
-
<i>Decoder<T></i>): <i>Decoder<T></i>
|
|
871
|
-
[<>](https://github.com/nvie/decoders/blob/master/src/lazy.js 'Source')<br />
|
|
872
|
-
|
|
873
|
-
Lazily evaluate the given decoder. This is useful to build self-referential types for
|
|
874
|
-
recursive data structures. Example:
|
|
875
|
-
|
|
876
|
-
```js
|
|
877
|
-
type Tree = {
|
|
878
|
-
value: string,
|
|
879
|
-
children: Array<Tree>,
|
|
880
|
-
// ^^^^
|
|
881
|
-
// Self-reference defining a recursive type
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
const treeDecoder: Decoder<Tree> = object({
|
|
885
|
-
value: string,
|
|
886
|
-
children: array(lazy(() => treeDecoder)),
|
|
887
|
-
// ^^^^^^^^^^^^^^^^^^^^^^^
|
|
888
|
-
// Use lazy() like this to refer to the treeDecoder which is
|
|
889
|
-
// getting defined here
|
|
41
|
+
createdAt: optional(iso8601),
|
|
42
|
+
tags: array(string),
|
|
890
43
|
});
|
|
891
|
-
```
|
|
892
44
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
```
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
45
|
+
//
|
|
46
|
+
// Call .verify() on the incoming data
|
|
47
|
+
//
|
|
48
|
+
const user = userDecoder.verify(externalData);
|
|
49
|
+
// ^^^^
|
|
50
|
+
// TypeScript can automatically infer this type now:
|
|
51
|
+
//
|
|
52
|
+
// {
|
|
53
|
+
// id: number;
|
|
54
|
+
// name: string;
|
|
55
|
+
// createdAt?: Date;
|
|
56
|
+
// tags: string[];
|
|
57
|
+
// }
|
|
58
|
+
//
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
<div id="$DecoderType"></div>
|
|
64
|
+
<div id="DecodeResult"></div>
|
|
65
|
+
<div id="Decoder"></div>
|
|
66
|
+
<div id="DecoderType"></div>
|
|
67
|
+
<div id="Guard"></div>
|
|
68
|
+
<div id="JSONArray"></div>
|
|
69
|
+
<div id="JSONObject"></div>
|
|
70
|
+
<div id="JSONValue"></div>
|
|
71
|
+
<div id="Scalar"></div>
|
|
72
|
+
<div id="adding-predicates"></div>
|
|
73
|
+
<div id="always"></div>
|
|
74
|
+
<div id="anyNumber"></div>
|
|
75
|
+
<div id="array"></div>
|
|
76
|
+
<div id="boolean"></div>
|
|
77
|
+
<div id="building-custom-decoders"></div>
|
|
78
|
+
<div id="compose"></div>
|
|
79
|
+
<div id="compositions"></div>
|
|
80
|
+
<div id="constant"></div>
|
|
81
|
+
<div id="date"></div>
|
|
82
|
+
<div id="define"></div>
|
|
83
|
+
<div id="describe"></div>
|
|
84
|
+
<div id="dict"></div>
|
|
85
|
+
<div id="either"></div>
|
|
86
|
+
<div id="email"></div>
|
|
87
|
+
<div id="exact"></div>
|
|
88
|
+
<div id="fail"></div>
|
|
89
|
+
<div id="guard"></div>
|
|
90
|
+
<div id="hardcoded"></div>
|
|
91
|
+
<div id="httpsUrl"></div>
|
|
92
|
+
<div id="inexact"></div>
|
|
93
|
+
<div id="instanceOf"></div>
|
|
94
|
+
<div id="integer"></div>
|
|
95
|
+
<div id="iso8601"></div>
|
|
96
|
+
<div id="json"></div>
|
|
97
|
+
<div id="jsonArray"></div>
|
|
98
|
+
<div id="jsonObject"></div>
|
|
99
|
+
<div id="lazy"></div>
|
|
100
|
+
<div id="mapping"></div>
|
|
101
|
+
<div id="maybe"></div>
|
|
102
|
+
<div id="mixed"></div>
|
|
103
|
+
<div id="never"></div>
|
|
104
|
+
<div id="nonEmptyArray"></div>
|
|
105
|
+
<div id="nonEmptyString"></div>
|
|
106
|
+
<div id="null_"></div>
|
|
107
|
+
<div id="nullable"></div>
|
|
108
|
+
<div id="number"></div>
|
|
109
|
+
<div id="numericBoolean"></div>
|
|
110
|
+
<div id="object"></div>
|
|
111
|
+
<div id="oneOf"></div>
|
|
112
|
+
<div id="optional"></div>
|
|
113
|
+
<div id="poja"></div>
|
|
114
|
+
<div id="pojo"></div>
|
|
115
|
+
<div id="positiveInteger"></div>
|
|
116
|
+
<div id="positiveNumber"></div>
|
|
117
|
+
<div id="predicate"></div>
|
|
118
|
+
<div id="prep"></div>
|
|
119
|
+
<div id="primitives"></div>
|
|
120
|
+
<div id="regex"></div>
|
|
121
|
+
<div id="set"></div>
|
|
122
|
+
<div id="string"></div>
|
|
123
|
+
<div id="taggedUnion"></div>
|
|
124
|
+
<div id="the-difference-between-object-exact-and-inexact"></div>
|
|
125
|
+
<div id="transform"></div>
|
|
126
|
+
<div id="transformation"></div>
|
|
127
|
+
<div id="truthy"></div>
|
|
128
|
+
<div id="tuple"></div>
|
|
129
|
+
<div id="undefined_"></div>
|
|
130
|
+
<div id="unknown"></div>
|
|
131
|
+
<div id="url"></div>
|
|
132
|
+
<div id="uuid"></div>
|
|
133
|
+
<div id="uuidv1"></div>
|
|
134
|
+
<div id="uuidv4"></div>
|
|
135
|
+
|
|
136
|
+
Documentation for v1 can be found
|
|
137
|
+
[here](https://github.com/nvie/decoders/tree/v1.25.5#readme).
|
|
138
|
+
Documentation for v2 (currently in beta) can be found on
|
|
139
|
+
[https://decoders.cc](https://decoders.cc).
|