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.
Files changed (165) hide show
  1. package/CHANGELOG.md +53 -5
  2. package/Decoder.d.ts +94 -0
  3. package/Decoder.js +222 -0
  4. package/Decoder.js.flow +286 -0
  5. package/Decoder.mjs +215 -0
  6. package/NotSupportedTSVersion.d.ts +1 -0
  7. package/README.md +124 -961
  8. package/_utils.d.ts +9 -0
  9. package/{cjs/_utils.js → _utils.js} +12 -18
  10. package/{cjs/_utils.js.flow → _utils.js.flow} +15 -19
  11. package/{es/_utils.js → _utils.mjs} +11 -15
  12. package/{ts/annotate.d.ts → annotate.d.ts} +25 -21
  13. package/{cjs/annotate.js → annotate.js} +0 -0
  14. package/{cjs/annotate.js.flow → annotate.js.flow} +0 -0
  15. package/{es/annotate.js → annotate.mjs} +0 -0
  16. package/format.d.ts +6 -0
  17. package/{cjs/format/inline.js → format.js} +7 -2
  18. package/{cjs/format/inline.js.flow → format.js.flow} +9 -3
  19. package/{es/format/inline.js → format.mjs} +5 -2
  20. package/index.d.ts +40 -0
  21. package/index.js +89 -0
  22. package/index.js.flow +44 -0
  23. package/index.mjs +11 -0
  24. package/{ts → lib}/_helpers.d.ts +0 -0
  25. package/lib/arrays.d.ts +59 -0
  26. package/lib/arrays.js +139 -0
  27. package/lib/arrays.js.flow +138 -0
  28. package/lib/arrays.mjs +124 -0
  29. package/lib/basics.d.ts +93 -0
  30. package/lib/basics.js +144 -0
  31. package/lib/basics.js.flow +124 -0
  32. package/lib/basics.mjs +120 -0
  33. package/lib/booleans.d.ts +16 -0
  34. package/lib/booleans.js +35 -0
  35. package/lib/booleans.js.flow +22 -0
  36. package/lib/booleans.mjs +25 -0
  37. package/lib/dates.d.ts +15 -0
  38. package/lib/dates.js +44 -0
  39. package/lib/dates.js.flow +40 -0
  40. package/lib/dates.mjs +34 -0
  41. package/lib/json.d.ts +35 -0
  42. package/lib/json.js +55 -0
  43. package/lib/json.js.flow +50 -0
  44. package/lib/json.mjs +40 -0
  45. package/lib/numbers.d.ts +31 -0
  46. package/lib/numbers.js +51 -0
  47. package/lib/numbers.js.flow +48 -0
  48. package/lib/numbers.mjs +41 -0
  49. package/lib/objects.d.ts +75 -0
  50. package/lib/objects.js +240 -0
  51. package/lib/objects.js.flow +246 -0
  52. package/lib/objects.mjs +223 -0
  53. package/lib/strings.d.ts +56 -0
  54. package/lib/strings.js +101 -0
  55. package/lib/strings.js.flow +90 -0
  56. package/lib/strings.mjs +82 -0
  57. package/lib/unions.d.ts +55 -0
  58. package/lib/unions.js +160 -0
  59. package/lib/unions.js.flow +155 -0
  60. package/lib/unions.mjs +146 -0
  61. package/lib/utilities.d.ts +34 -0
  62. package/lib/utilities.js +75 -0
  63. package/lib/utilities.js.flow +65 -0
  64. package/lib/utilities.mjs +60 -0
  65. package/package.json +79 -29
  66. package/result.d.ts +16 -0
  67. package/result.js +34 -0
  68. package/result.js.flow +26 -0
  69. package/result.mjs +27 -0
  70. package/cjs/_guard.js +0 -26
  71. package/cjs/_guard.js.flow +0 -20
  72. package/cjs/_types.js +0 -1
  73. package/cjs/_types.js.flow +0 -20
  74. package/cjs/format/index.js +0 -12
  75. package/cjs/format/index.js.flow +0 -4
  76. package/cjs/format/short.js +0 -10
  77. package/cjs/format/short.js.flow +0 -8
  78. package/cjs/index.js +0 -120
  79. package/cjs/index.js.flow +0 -63
  80. package/cjs/result.js +0 -172
  81. package/cjs/result.js.flow +0 -166
  82. package/cjs/stdlib/array.js +0 -108
  83. package/cjs/stdlib/array.js.flow +0 -103
  84. package/cjs/stdlib/boolean.js +0 -44
  85. package/cjs/stdlib/boolean.js.flow +0 -29
  86. package/cjs/stdlib/composition.js +0 -56
  87. package/cjs/stdlib/composition.js.flow +0 -43
  88. package/cjs/stdlib/constants.js +0 -69
  89. package/cjs/stdlib/constants.js.flow +0 -46
  90. package/cjs/stdlib/date.js +0 -46
  91. package/cjs/stdlib/date.js.flow +0 -40
  92. package/cjs/stdlib/describe.js +0 -26
  93. package/cjs/stdlib/describe.js.flow +0 -17
  94. package/cjs/stdlib/dispatch.js +0 -62
  95. package/cjs/stdlib/dispatch.js.flow +0 -58
  96. package/cjs/stdlib/either.js +0 -117
  97. package/cjs/stdlib/either.js.flow +0 -151
  98. package/cjs/stdlib/fail.js +0 -21
  99. package/cjs/stdlib/fail.js.flow +0 -12
  100. package/cjs/stdlib/instanceOf.js +0 -19
  101. package/cjs/stdlib/instanceOf.js.flow +0 -20
  102. package/cjs/stdlib/json.js +0 -31
  103. package/cjs/stdlib/json.js.flow +0 -28
  104. package/cjs/stdlib/lazy.js +0 -16
  105. package/cjs/stdlib/lazy.js.flow +0 -15
  106. package/cjs/stdlib/mapping.js +0 -67
  107. package/cjs/stdlib/mapping.js.flow +0 -54
  108. package/cjs/stdlib/number.js +0 -40
  109. package/cjs/stdlib/number.js.flow +0 -34
  110. package/cjs/stdlib/object.js +0 -194
  111. package/cjs/stdlib/object.js.flow +0 -203
  112. package/cjs/stdlib/optional.js +0 -54
  113. package/cjs/stdlib/optional.js.flow +0 -41
  114. package/cjs/stdlib/string.js +0 -98
  115. package/cjs/stdlib/string.js.flow +0 -82
  116. package/cjs/stdlib/tuple.js +0 -173
  117. package/cjs/stdlib/tuple.js.flow +0 -220
  118. package/es/_guard.js +0 -15
  119. package/es/_types.js +0 -0
  120. package/es/format/index.js +0 -2
  121. package/es/format/short.js +0 -4
  122. package/es/index.js +0 -37
  123. package/es/result.js +0 -139
  124. package/es/stdlib/array.js +0 -91
  125. package/es/stdlib/boolean.js +0 -28
  126. package/es/stdlib/composition.js +0 -42
  127. package/es/stdlib/constants.js +0 -46
  128. package/es/stdlib/date.js +0 -28
  129. package/es/stdlib/describe.js +0 -16
  130. package/es/stdlib/dispatch.js +0 -51
  131. package/es/stdlib/either.js +0 -90
  132. package/es/stdlib/fail.js +0 -11
  133. package/es/stdlib/instanceOf.js +0 -8
  134. package/es/stdlib/json.js +0 -15
  135. package/es/stdlib/lazy.js +0 -11
  136. package/es/stdlib/mapping.js +0 -54
  137. package/es/stdlib/number.js +0 -25
  138. package/es/stdlib/object.js +0 -175
  139. package/es/stdlib/optional.js +0 -38
  140. package/es/stdlib/string.js +0 -76
  141. package/es/stdlib/tuple.js +0 -155
  142. package/ts/_guard.d.ts +0 -7
  143. package/ts/_types.d.ts +0 -16
  144. package/ts/_utils.d.ts +0 -13
  145. package/ts/array.d.ts +0 -5
  146. package/ts/boolean.d.ts +0 -5
  147. package/ts/constants.d.ts +0 -11
  148. package/ts/date.d.ts +0 -4
  149. package/ts/describe.d.ts +0 -3
  150. package/ts/dispatch.d.ts +0 -8
  151. package/ts/either.d.ts +0 -61
  152. package/ts/fail.d.ts +0 -3
  153. package/ts/index.d.ts +0 -42
  154. package/ts/inline.d.ts +0 -3
  155. package/ts/instanceOf.d.ts +0 -3
  156. package/ts/json.d.ts +0 -11
  157. package/ts/lazy.d.ts +0 -3
  158. package/ts/mapping.d.ts +0 -4
  159. package/ts/number.d.ts +0 -6
  160. package/ts/object.d.ts +0 -33
  161. package/ts/optional.d.ts +0 -5
  162. package/ts/result.d.ts +0 -39
  163. package/ts/short.d.ts +0 -3
  164. package/ts/string.d.ts +0 -7
  165. 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="330" height="64" /><br />
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
  [![npm](https://img.shields.io/npm/v/decoders.svg)](https://www.npmjs.com/package/decoders)
4
4
  [![Build Status](https://github.com/nvie/decoders/workflows/test/badge.svg)](https://github.com/nvie/decoders/actions)
5
- [![Coverage Status](https://img.shields.io/coveralls/nvie/decoders/master.svg)](https://coveralls.io/github/nvie/decoders?branch=master)
5
+ [![Coverage Status](https://img.shields.io/coveralls/nvie/decoders/main.svg)](https://coveralls.io/github/nvie/decoders?branch=main)
6
6
  [![Minified Size](https://badgen.net/bundlephobia/minzip/decoders)](https://bundlephobia.com/result?p=decoders)
7
7
 
8
- Elegant and battle-tested validation library for type-safe input data for TypeScript and
9
- Flow. The API is inspired by Elm’s JSON decoders, hence the name.
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
- See https://nvie.com/posts/introducing-decoders/ for an introduction.
11
+ ## Motivation
12
12
 
13
- ## Why?
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
- If you're using Flow or TypeScript to statically typecheck your JavaScript, you'll know
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&lt;number&gt;</i>
82
- [&lt;&gt;](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&lt;integer&gt;</i>
99
- [&lt;&gt;](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&lt;string&gt;</i>
114
- [&lt;&gt;](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&lt;string&gt;</i>
128
- [&lt;&gt;](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&lt;string&gt;</i>
143
- [&lt;&gt;](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&lt;string&gt;</i>
157
- [&lt;&gt;](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&lt;boolean&gt;</i>
170
- [&lt;&gt;](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&lt;boolean&gt;</i>
186
- [&lt;&gt;](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&lt;boolean&gt;</i>
206
- [&lt;&gt;](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&lt;Date&gt;</i>
224
- [&lt;&gt;](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&lt;Date&gt;</i>
241
- [&lt;&gt;](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&lt;null&gt;</i>
261
- [&lt;&gt;](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&lt;void&gt;</i>
277
- [&lt;&gt;](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>&lt;T&gt;</i>(value: T):
292
- <i>Decoder&lt;T&gt;</i>
293
- [&lt;&gt;](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
- const mydecoder = guard(constant('hello'));
308
- mydecoder('hello') === 'hello';
309
- mydecoder('this breaks'); // DecodeError
310
- mydecoder(false); // DecodeError
311
- mydecoder(undefined); // DecodeError
312
- ```
313
-
314
- ---
315
-
316
- <a name="hardcoded" href="#hardcoded">#</a> <b>hardcoded</b><i>&lt;T&gt;</i>(value: T):
317
- <i>Decoder&lt;T&gt;</i>
318
- [&lt;&gt;](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&lt;empty&gt;</i>
333
- [&lt;&gt;](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&lt;mixed&gt;</i>
348
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/constants.js 'Source')<br />
349
- <a name="unknown" href="#unknown">#</a> <b>unknown</b>: <i>Decoder&lt;unknown&gt;</i>
350
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T | void&gt;</i>
375
- [&lt;&gt;](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
- ```javascript
392
- object({
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
- address: optional(string),
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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T | null&gt;</i>
413
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
430
- <i>Decoder&lt;?T&gt;</i>
431
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
448
- <i>Decoder&lt;Array&lt;T&gt;&gt;</i>
449
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
464
- <i>Decoder&lt;Array&lt;T&gt;&gt;</i>
465
- [&lt;&gt;](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>&lt;T1&gt;</i>(<i>Decoder&lt;T1&gt;</i>): <i>Decoder&lt;[T1]&gt;</i>
480
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
481
- <a name="tuple2" href="#tuple2">#</a> <b>tuple2</b><i>&lt;T1,
482
- T2&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>): <i>Decoder&lt;[T1,
483
- T2]&gt;</i>
484
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
485
- <a name="tuple3" href="#tuple3">#</a> <b>tuple3</b><i>&lt;T1, T2,
486
- T3&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>, <i>Decoder&lt;T3&gt;</i>):
487
- <i>Decoder&lt;[T1, T2, T3]&gt;</i>
488
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
489
- <a name="tuple4" href="#tuple4">#</a> <b>tuple4</b><i>&lt;T1, T2, T3,
490
- T4&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>, <i>Decoder&lt;T3&gt;</i>,
491
- <i>Decoder&lt;T4&gt;</i>): <i>Decoder&lt;[T1, T2, T3, T4]&gt;</i>
492
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
493
- <a name="tuple5" href="#tuple5">#</a> <b>tuple5</b><i>&lt;T1, T2, T3, T4,
494
- T5&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>, <i>Decoder&lt;T3&gt;</i>,
495
- <i>Decoder&lt;T3&gt;</i>, <i>Decoder&lt;T4&gt;</i>, <i>Decoder&lt;T5&gt;</i>):
496
- <i>Decoder&lt;[T1, T2, T3, T4, T5]&gt;</i>
497
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/tuple.js 'Source')<br />
498
- <a name="tuple6" href="#tuple6">#</a> <b>tuple6</b><i>&lt;T1, T2, T3, T4, T5,
499
- T6&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>, <i>Decoder&lt;T3&gt;</i>,
500
- <i>Decoder&lt;T4&gt;</i>, <i>Decoder&lt;T5&gt;</i>, <i>Decoder&lt;T6&gt;</i>):
501
- <i>Decoder&lt;[T1, T2, T3, T4, T5, T6]&gt;</i>
502
- [&lt;&gt;](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>&lt;O: { [field: string]:
517
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
518
- [&lt;&gt;](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>&lt;O: { [field: string]:
541
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
542
- [&lt;&gt;](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>&lt;O: { [field: string]:
564
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
565
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;Map&lt;string,
589
- T&gt;&gt;</i>
590
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
617
- <i>Decoder&lt;{ [string]: &lt;T&gt;}&gt;</i>
618
- [&lt;&gt;](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&lt;JSONValue&gt;</i>
644
- [&lt;&gt;](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&lt;JSONObject&gt;</i>
672
- [&lt;&gt;](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&lt;JSONArray&gt;</i>
692
- [&lt;&gt;](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>&lt;T1,
711
- T2&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>): <i>Decoder&lt;T1 |
712
- T2&gt;</i><br />
713
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
714
- <a name="either2" href="#either2">#</a> <b>either2</b><i>&lt;T1,
715
- T2&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>): <i>Decoder&lt;T1 |
716
- T2&gt;</i><br />
717
- [&lt;&gt;](https://github.com/nvie/decoders/blob/master/src/either.js 'Source')<br />
718
- <a name="either3" href="#either3">#</a> <b>either3</b><i>&lt;T1, T2,
719
- T3&gt;</i>(<i>Decoder&lt;T1&gt;</i>, <i>Decoder&lt;T2&gt;</i>, <i>Decoder&lt;T3&gt;</i>):
720
- <i>Decoder&lt;T1 | T2 | T3&gt;</i>
721
- [&lt;&gt;](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>&lt;O: { [field: string]:
737
- (Decoder&lt;T&gt; | Decoder&lt;V&gt; | ...) }&gt;</i>(field: string, mapping: O):
738
- <i>Decoder&lt;T | V | ...&gt;</i>
739
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Array&lt;T&gt;</i>):
768
- <i>Decoder&lt;T&gt;</i>
769
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Class&lt;T&gt;</i>): <i>Decoder&lt;T&gt;</i>
798
- [&lt;&gt;](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>&lt;T, V&gt;</i>(<i>Decoder&lt;T&gt;</i>,
817
- <i>&lt;T&gt;</i> =&gt; <i>&lt;V&gt;</i>): <i>Decoder&lt;V&gt;</i>
818
- [&lt;&gt;](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>&lt;T,
836
- V&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>Decoder&lt;V, T&gt;</i>): <i>Decoder&lt;V&gt;</i>
837
- [&lt;&gt;](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>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>string</i>):
853
- <i>Decoder&lt;T&gt;</i>
854
- [&lt;&gt;](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>&lt;T&gt;</i>(() =>
870
- <i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T&gt;</i>
871
- [&lt;&gt;](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
- ### The difference between `object`, `exact`, and `inexact`
894
-
895
- The three decoders in the "object" family of decoders only differ in how they treat extra
896
- properties on input values.
897
-
898
- For example, for a definition like:
899
-
900
- ```js
901
- import { exact, inexact, number, object, string } from 'decoders';
902
-
903
- const thing = {
904
- a: string,
905
- b: number,
906
- };
907
- ```
908
-
909
- And a runtime input of:
910
-
911
- ```js
912
- {
913
- a: "hi",
914
- b: 42,
915
- c: "extra", // Note "c" is not a known field
916
- }
917
- ```
918
-
919
- | | Extra properties | Output value | Inferred type |
920
- | ---------------- | ---------------- | ------------------------------ | ----------------------------------------- |
921
- | `object(thing)` | discarded | `{a: "hi", b: 42}` | `{a: string, b: number}` |
922
- | `exact(thing)` | not allowed | ⚡️ Runtime error | `{a: string, b: number}` |
923
- | `inexact(thing)` | retained | `{a: "hi", b: 42, c: "extra"}` | `{a: string, b: number, [string]: mixed}` |
924
-
925
- ### Building custom decoders
926
-
927
- There are two main building blocks for defining your own custom decoders: `map()` and
928
- `compose()`.
929
-
930
- There are roughly 3 use cases that you will want to use:
931
-
932
- 1. **[Transformation](#transformation)** (i.e. read one type, but return another, or read
933
- a type but change its value before returning)
934
- 1. **[Adding extra value requirements](#adding-predicates)** (i.e. decode using an
935
- existing decoder, but require an extra value check)
936
- 1. **Chaining** multiple decoders (less common, more advanced)
937
-
938
- #### Transformation
939
-
940
- To read one type from the input, but return another, use:
941
-
942
- ```js
943
- const numericString: Decoder<number> = map(
944
- // At runtime, expect to read a string...
945
- string,
946
- // ...but return it as a number
947
- (s) => Number(s)
948
- );
949
- ```
950
-
951
- To read one type, but change its value before returning:
952
-
953
- ```js
954
- const upperCase: Decoder<string> = map(string, (s) => s.toUpperCase());
955
- ```
956
-
957
- **WARNING:** While you can map anything to anything, it's typically **NOT A GOOD IDEA to
958
- put too much transformation logic inside decoders**. It's recommended to keep them minimal
959
- and only try to use them for the most basic use cases, like in the examples above. Keeping
960
- business logic outside decoders makes them more reusable and composable.
961
-
962
- #### Adding predicates
963
-
964
- The easiest way to decode using an existing decoder, but enforcing extra runtime checks on
965
- their values is by using the `compose(..., predicate(...))` construction:
966
-
967
- ```js
968
- const odd = compose(
969
- integer,
970
- predicate((n) => n % 2 !== 0, 'Must be odd')
971
- );
972
- const shortString = compose(
973
- string,
974
- predicate((s) => s.length < 8, 'Must be less than 8 chars')
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).