decoders 2.0.0-beta9 → 2.0.0

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 (136) hide show
  1. package/CHANGELOG.md +56 -29
  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/README.md +122 -1507
  7. package/_utils.d.ts +0 -1
  8. package/_utils.js +11 -17
  9. package/_utils.js.flow +13 -17
  10. package/_utils.mjs +10 -14
  11. package/format.d.ts +4 -2
  12. package/format.js +1 -1
  13. package/format.js.flow +3 -1
  14. package/format.mjs +1 -1
  15. package/index.d.ts +29 -31
  16. package/index.js +62 -84
  17. package/index.js.flow +30 -48
  18. package/index.mjs +11 -36
  19. package/{core → lib}/_helpers.d.ts +0 -0
  20. package/lib/arrays.d.ts +59 -0
  21. package/lib/arrays.js +139 -0
  22. package/lib/arrays.js.flow +138 -0
  23. package/lib/arrays.mjs +124 -0
  24. package/lib/basics.d.ts +93 -0
  25. package/lib/basics.js +144 -0
  26. package/lib/basics.js.flow +124 -0
  27. package/lib/basics.mjs +120 -0
  28. package/lib/booleans.d.ts +16 -0
  29. package/lib/booleans.js +35 -0
  30. package/lib/booleans.js.flow +22 -0
  31. package/lib/booleans.mjs +25 -0
  32. package/lib/dates.d.ts +15 -0
  33. package/lib/dates.js +44 -0
  34. package/lib/dates.js.flow +40 -0
  35. package/lib/dates.mjs +34 -0
  36. package/lib/json.d.ts +35 -0
  37. package/lib/json.js +55 -0
  38. package/lib/json.js.flow +50 -0
  39. package/lib/json.mjs +40 -0
  40. package/lib/numbers.d.ts +31 -0
  41. package/lib/numbers.js +51 -0
  42. package/lib/numbers.js.flow +48 -0
  43. package/lib/numbers.mjs +41 -0
  44. package/lib/objects.d.ts +75 -0
  45. package/{core/object.js → lib/objects.js} +78 -85
  46. package/{core/object.js.flow → lib/objects.js.flow} +89 -102
  47. package/{core/object.mjs → lib/objects.mjs} +77 -82
  48. package/lib/strings.d.ts +56 -0
  49. package/lib/strings.js +101 -0
  50. package/lib/strings.js.flow +90 -0
  51. package/lib/strings.mjs +82 -0
  52. package/lib/unions.d.ts +55 -0
  53. package/lib/unions.js +160 -0
  54. package/{core/either.js.flow → lib/unions.js.flow} +67 -17
  55. package/lib/unions.mjs +146 -0
  56. package/lib/utilities.d.ts +34 -0
  57. package/lib/utilities.js +75 -0
  58. package/lib/utilities.js.flow +65 -0
  59. package/lib/utilities.mjs +60 -0
  60. package/package.json +64 -17
  61. package/result.d.ts +0 -23
  62. package/result.js +0 -68
  63. package/result.js.flow +0 -72
  64. package/result.mjs +0 -54
  65. package/_guard.d.ts +0 -7
  66. package/_guard.js +0 -22
  67. package/_guard.js.flow +0 -20
  68. package/_guard.mjs +0 -15
  69. package/_types.d.ts +0 -13
  70. package/_types.js +0 -1
  71. package/_types.js.flow +0 -20
  72. package/_types.mjs +0 -0
  73. package/core/array.d.ts +0 -8
  74. package/core/array.js +0 -115
  75. package/core/array.js.flow +0 -107
  76. package/core/array.mjs +0 -100
  77. package/core/boolean.d.ts +0 -5
  78. package/core/boolean.js +0 -40
  79. package/core/boolean.js.flow +0 -27
  80. package/core/boolean.mjs +0 -28
  81. package/core/composition.d.ts +0 -18
  82. package/core/composition.js +0 -82
  83. package/core/composition.js.flow +0 -74
  84. package/core/composition.mjs +0 -70
  85. package/core/constants.d.ts +0 -11
  86. package/core/constants.js +0 -65
  87. package/core/constants.js.flow +0 -44
  88. package/core/constants.mjs +0 -46
  89. package/core/date.d.ts +0 -4
  90. package/core/date.js +0 -42
  91. package/core/date.js.flow +0 -38
  92. package/core/date.mjs +0 -28
  93. package/core/describe.d.ts +0 -3
  94. package/core/describe.js +0 -22
  95. package/core/describe.js.flow +0 -17
  96. package/core/describe.mjs +0 -16
  97. package/core/dispatch.d.ts +0 -8
  98. package/core/dispatch.js +0 -60
  99. package/core/dispatch.js.flow +0 -59
  100. package/core/dispatch.mjs +0 -52
  101. package/core/either.d.ts +0 -66
  102. package/core/either.js +0 -101
  103. package/core/either.mjs +0 -90
  104. package/core/fail.d.ts +0 -3
  105. package/core/fail.js +0 -17
  106. package/core/fail.js.flow +0 -12
  107. package/core/fail.mjs +0 -11
  108. package/core/instanceOf.d.ts +0 -3
  109. package/core/instanceOf.js +0 -15
  110. package/core/instanceOf.js.flow +0 -20
  111. package/core/instanceOf.mjs +0 -8
  112. package/core/json.d.ts +0 -11
  113. package/core/json.js +0 -31
  114. package/core/json.js.flow +0 -28
  115. package/core/json.mjs +0 -15
  116. package/core/lazy.d.ts +0 -3
  117. package/core/lazy.js +0 -16
  118. package/core/lazy.js.flow +0 -15
  119. package/core/lazy.mjs +0 -11
  120. package/core/number.d.ts +0 -6
  121. package/core/number.js +0 -36
  122. package/core/number.js.flow +0 -40
  123. package/core/number.mjs +0 -25
  124. package/core/object.d.ts +0 -38
  125. package/core/optional.d.ts +0 -5
  126. package/core/optional.js +0 -50
  127. package/core/optional.js.flow +0 -41
  128. package/core/optional.mjs +0 -38
  129. package/core/string.d.ts +0 -13
  130. package/core/string.js +0 -80
  131. package/core/string.js.flow +0 -72
  132. package/core/string.mjs +0 -58
  133. package/core/tuple.d.ts +0 -30
  134. package/core/tuple.js +0 -54
  135. package/core/tuple.js.flow +0 -51
  136. package/core/tuple.mjs +0 -45
package/README.md CHANGED
@@ -1,1523 +1,138 @@
1
- <img alt="Decoders logo" src="./img/logo@2x.png" width="330" height="64" /><br />
1
+ <img alt="Decoders logo" src="./docs/assets/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
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
- ## Understanding decoders and guards
72
-
73
- At the heart, a decoder is a function that will take _any_ unsafe input, verify it, and
74
- either return an "ok" or an annotated "err" result. It will never throw an error when
75
- called.
76
-
77
- A guard is a convenience wrapper which will use the decoder
78
-
79
- ## API
80
-
81
- The decoders package consists of a few building blocks:
82
-
83
- - [Guards](#guards)
84
- - [Primitives](#primitives)
85
- - [Compositions](#compositions)
86
- - [Building custom decoders](#building-custom-decoders)
87
-
88
- ### Guards
89
-
90
- <a name="guard" href="#guard">#</a> <b>guard</b>(decoder: <i>Decoder&lt;T&gt;</i>,
91
- formatter?: <i>Annotation => string</i>): <i>Guard&lt;T&gt;</i>
92
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/_guard.js 'Source')
93
-
94
- Turns any given `Decoder<T>` into a `Guard<T>`.
95
-
96
- A guard works like a decoder, but will either:
97
-
98
- - Return the decoded value (aka the happy path)
99
- - Or throw an exception
100
-
101
- So a Guard bypasses the intermediate "Result" type that decoders output. An "ok" result
102
- will get returned, an "err" result will be formatted into an error message and thrown.
103
-
104
- The typical usage is that you keep composing decoders until you have one decoder for your
105
- entire input object, and then use a guard to wrap that outer decoder. Decoders can be
106
- composed to build larger decoders. Guards cannot be composed.
107
-
108
- #### Formatting error messsages
109
-
110
- By default, `guard()` will use the `formatInline` error formatter. You can pass another
111
- built-in formatter as the second argument, or provide your own. (This will require
112
- understanding the internal `Annotation` datastructure that decoders uses for error
113
- reporting.)
114
-
115
- Built-in formatters are:
116
-
117
- - `formatInline` (default) — will echo back the input object and inline error messages
118
- smartly. Example:
119
-
120
- ```typescript
121
- import { array, guard, object, string } from 'decoders';
122
- import { formatInline } from 'decoders/format';
123
-
124
- const mydecoder = array(object({ name: string, age: number }));
125
-
126
- const defaultGuard = guard(mydecoder, formatInline);
127
- defaultGuard([{ name: 'Alice', age: '33' }]);
128
- ```
129
-
130
- Will throw the following error message:
131
-
132
- ```text
133
- Decoding error:
134
- [
135
- {
136
- name: 'Alice',
137
- age: '33',
138
- ^^^^ Must be number
139
- },
140
- ]
141
- ```
142
-
143
- - `formatShort` — will report the _path_ into the object where the error happened.
144
- Example:
145
-
146
- ```typescript
147
- import { formatShort } from 'decoders/format';
148
- const customGuard = guard(mydecoder, formatShort);
149
- ```
150
-
151
- Will throw the following error message:
152
-
153
- ```text
154
- Decoding error: Value at keypath 0.age: Must be number
155
- ```
156
-
157
- ### Primitives
158
-
159
- <a name="number" href="#number">#</a> <b>number</b>: <i>Decoder&lt;number&gt;</i>
160
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
161
-
162
- Accepts only finite numbers (integer or float values). This means that values like `NaN`,
163
- or positive and negative `Infinity` are not considered valid numbers.
164
-
165
- <!-- prettier-ignore-start -->
166
- ```javascript
167
- const verify = guard(number);
168
-
169
- // 👍
170
- verify(123) === 123;
171
- verify(-3.14) === -3.14;
172
-
173
- // 👎
174
- verify(Infinity); // throws
175
- verify(NaN); // throws
176
- verify('not a number'); // throws
177
- ```
178
- <!-- prettier-ignore-end -->
179
-
180
- ---
181
-
182
- <a name="integer" href="#integer">#</a> <b>integer</b>: <i>Decoder&lt;integer&gt;</i>
183
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
184
-
185
- Like `number`, but only accepts values that are whole numbers.
186
-
187
- <!-- prettier-ignore-start -->
188
- ```javascript
189
- const verify = guard(integer);
190
-
191
- // 👍
192
- verify(123) === 123;
193
-
194
- // 👎
195
- verify(-3.14); // throws
196
- verify(Infinity); // throws
197
- verify(NaN); // throws
198
- verify('not a integer'); // throws
199
- ```
200
- <!-- prettier-ignore-end -->
201
-
202
- ---
203
-
204
- <a name="positiveNumber" href="#positiveNumber">#</a> <b>positiveNumber</b>:
205
- <i>Decoder&lt;number&gt;</i>
206
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
207
-
208
- Accepts only positive finite numbers (integer or float values).
209
-
210
- <!-- prettier-ignore-start -->
211
- ```javascript
212
- const verify = guard(positiveNumber);
213
-
214
- // 👍
215
- verify(123) === 123;
216
-
217
- // 👎
218
- verify(-42); // throws
219
- verify(3.14); // throws
220
- verify(Infinity); // throws
221
- verify(NaN); // throws
222
- verify('not a number'); // throws
223
- ```
224
- <!-- prettier-ignore-end -->
225
-
226
- ---
227
-
228
- <a name="positiveInteger" href="#positiveInteger">#</a> <b>positiveInteger</b>:
229
- <i>Decoder&lt;number&gt;</i>
230
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/number.js 'Source')
231
-
232
- Accepts only positive finite integers.
233
-
234
- <!-- prettier-ignore-start -->
235
- ```javascript
236
- const verify = guard(positiveInteger);
237
-
238
- // 👍
239
- verify(123) === 123;
240
-
241
- // 👎
242
- verify(-3); // throws
243
- verify(3.14); // throws
244
- verify(Infinity); // throws
245
- verify(NaN); // throws
246
- verify('not a number'); // throws
247
- ```
248
- <!-- prettier-ignore-end -->
249
-
250
- ---
251
-
252
- <a name="string" href="#string">#</a> <b>string</b>: <i>Decoder&lt;string&gt;</i>
253
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
254
-
255
- Accepts only string values.
256
-
257
- <!-- prettier-ignore-start -->
258
- ```javascript
259
- const verify = guard(string);
260
-
261
- // 👍
262
- verify('hello world') === 'hello world';
263
- verify('🚀') === '🚀';
264
- verify('') === '';
265
-
266
- // 👎
267
- verify(123); // throws
268
- verify(true); // throws
269
- verify(null); // throws
270
- ```
271
- <!-- prettier-ignore-end -->
272
-
273
- ---
274
-
275
- <a name="nonEmptyString" href="#nonEmptyString">#</a> <b>nonEmptyString</b>:
276
- <i>Decoder&lt;string&gt;</i>
277
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
278
-
279
- Like `string`, but will reject the empty string, or strings containing only whitespace.
280
-
281
- <!-- prettier-ignore-start -->
282
- ```javascript
283
- const verify = guard(nonEmptyString);
284
-
285
- // 👍
286
- verify('hello world') === 'hello world';
287
- verify('🚀') === '🚀';
288
-
289
- // 👎
290
- verify(123); // throws
291
- verify(' '); // throws
292
- verify(''); // throws
293
- ```
294
- <!-- prettier-ignore-end -->
295
-
296
- ---
297
-
298
- <a name="regex" href="#regex">#</a> <b>regex</b>(): <i>Decoder&lt;string&gt;</i>
299
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
300
-
301
- Accepts only string values that match the given regular expression.
302
-
303
- <!-- prettier-ignore-start -->
304
- ```javascript
305
- const verify = guard(regex(/^[0-9][0-9]+$/));
306
-
307
- // 👍
308
- verify('42') === '42';
309
- verify('83401648364738') === '83401648364738';
310
-
311
- // 👎
312
- verify(''); // throws
313
- verify('1'); // throws
314
- verify('foo'); // throws
315
- ```
316
- <!-- prettier-ignore-end -->
317
-
318
- ---
319
-
320
- <a name="email" href="#email">#</a> <b>email</b>: <i>Decoder&lt;string&gt;</i>
321
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
322
-
323
- Accepts only strings that are syntactically valid email addresses. (This will not mean
324
- that the email address actually exist.)
325
-
326
- <!-- prettier-ignore-start -->
327
- ```javascript
328
- const verify = guard(email);
329
-
330
- // 👍
331
- verify('alice@acme.org') === 'alice@acme.org';
332
-
333
- // 👎
334
- verify('foo'); // throws
335
- verify('@acme.org'); // throws
336
- verify('alice @ acme.org'); // throws
337
- ```
338
- <!-- prettier-ignore-end -->
339
-
340
- ---
341
-
342
- <a name="url" href="#url">#</a> <b>url</b>: <i>Decoder&lt;URL&gt;</i>
343
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
344
-
345
- Accepts strings that are valid URLs, returns the value as a URL instance.
346
-
347
- <!-- prettier-ignore-start -->
348
- ```javascript
349
- const verify = guard(url);
350
-
351
- // 👍
352
- verify('http://nvie.com') === new URL('http://nvie.com/');
353
- verify('https://nvie.com') === new URL('https://nvie.com/');
354
- verify('git+ssh://user@github.com/foo/bar.git') === new URL('git+ssh://user@github.com/foo/bar.git');
355
-
356
- // 👎
357
- verify('foo'); // throws
358
- verify('@acme.org'); // throws
359
- verify('alice @ acme.org'); // throws
360
- verify('/search?q=foo'); // throws
361
- ```
362
- <!-- prettier-ignore-end -->
363
-
364
- ---
365
-
366
- <a name="httpsUrl" href="#httpsUrl">#</a> <b>httpsUrl</b>: <i>Decoder&lt;URL&gt;</i>
367
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
368
-
369
- Accepts strings that are valid URLs, but only HTTPS ones. Returns the value as a URL
370
- instance.
371
-
372
- <!-- prettier-ignore-start -->
373
- ```javascript
374
- const verify = guard(httpsUrl);
375
-
376
- // 👍
377
- verify('https://nvie.com:443') === new URL('https://nvie.com/');
378
-
379
- // 👎
380
- verify('http://nvie.com'); // throws, not HTTPS
381
- verify('git+ssh://user@github.com/foo/bar.git'); // throws, not HTTPS
382
- ```
383
- <!-- prettier-ignore-end -->
384
-
385
- **Tip!** If you need to limit URLs to different protocols than HTTP, you can do as the
386
- HTTPS decoder is implemented: as a predicate on top of a regular `url` decoder.
20
+ ## Example
387
21
 
388
22
  ```typescript
389
- import { predicate, url } from 'decoders';
390
-
391
- const gitUrl: Decoder<URL> = predicate(
392
- url,
393
- (value) => value.protocol === 'git:',
394
- 'Must be a git:// URL',
395
- );
396
- ```
397
-
398
- ---
399
-
400
- <a name="uuid" href="#uuid">#</a> <b>uuid</b>: <i>Decoder&lt;string&gt;</i>
401
- [(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
402
-
403
- Accepts strings that are valid [UUIDs][wiki-uuid] (universally unique identifier).
404
-
405
- <!-- prettier-ignore-start -->
406
- ```javascript
407
- const verify = guard(uuid);
408
-
409
- // 👍
410
- verify('123e4567-e89b-12d3-a456-426614174000') === '123e4567-e89b-12d3-a456-426614174000'
411
- verify('123E4567-E89B-12D3-A456-426614174000') === '123E4567-E89B-12D3-A456-426614174000'
412
-
413
- // 👎
414
- verify('123E4567E89B12D3A456426614174000'); // throws
415
- verify('abcdefgh-ijkl-mnop-qrst-uvwxyz012345'); // throws
416
- ```
417
- <!-- prettier-ignore-end -->
418
-
419
- ---
420
-
421
- <a name="uuidv1" href="#uuidv1">#</a> <b>uuidv1</b>: <i>Decoder&lt;string&gt;</i>
422
- [(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
423
-
424
- Like `uuid`, but only accepts [UUIDv1s][wiki-uuidv1] strings.
425
-
426
- <!-- prettier-ignore-start -->
427
- ```javascript
428
- const verify = guard(uuidv1);
429
-
430
- // 👍
431
- verify('123e4567-e89b-12d3-a456-426614174000') === '123e4567-e89b-42d3-a456-426614174000'
432
-
433
- // 👎
434
- verify('123e4567-e89b-42d3-a456-426614174000') // throws
435
- ```
436
- <!-- prettier-ignore-end -->
437
-
438
- ---
439
-
440
- <a name="uuidv4" href="#uuidv4">#</a> <b>uuidv4</b>: <i>Decoder&lt;string&gt;</i>
441
- [(source)](https://github.com/nvie/decoders/blob/main/src/core/string.js 'Source')
442
-
443
- Like `uuid`, but only accepts [UUIDv4s][wiki-uuidv4] strings.
444
-
445
- <!-- prettier-ignore-start -->
446
- ```javascript
447
- const verify = guard(uuidv4);
448
-
449
- // 👍
450
- verify('123e4567-e89b-42d3-a456-426614174000') === '123e4567-e89b-42d3-a456-426614174000'
451
-
452
- // 👎
453
- verify('123e4567-e89b-12d3-a456-426614174000') // throws
454
- ```
455
- <!-- prettier-ignore-end -->
456
-
457
- ---
458
-
459
- <a name="boolean" href="#boolean">#</a> <b>boolean</b>: <i>Decoder&lt;boolean&gt;</i>
460
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
461
-
462
- Accepts only boolean values.
463
-
464
- <!-- prettier-ignore-start -->
465
- ```javascript
466
- const verify = guard(boolean);
467
-
468
- // 👍
469
- verify(false) === false;
470
- verify(true) === true;
471
-
472
- // 👎
473
- verify(undefined); // throws
474
- verify('hello world'); // throws
475
- verify(123); // throws
476
- ```
477
- <!-- prettier-ignore-end -->
478
-
479
- ---
480
-
481
- <a name="truthy" href="#truthy">#</a> <b>truthy</b>: <i>Decoder&lt;boolean&gt;</i>
482
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
483
-
484
- Accepts any value and will return its "truth" value. Will never reject.
485
-
486
- ```javascript
487
- const verify = guard(truthy);
488
-
489
- // 👍
490
- verify(false) === false;
491
- verify(true) === true;
492
- verify(undefined) === false;
493
- verify('hello world') === true;
494
- verify('false') === true;
495
- verify(0) === false;
496
- verify(1) === true;
497
- verify(null) === false;
498
-
499
- // 👎
500
- // This decoder will never reject an input
501
- ```
502
-
503
- ---
504
-
505
- <a name="numericBoolean" href="#numericBoolean">#</a> <b>numericBoolean</b>:
506
- <i>Decoder&lt;boolean&gt;</i>
507
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/boolean.js 'Source')
508
-
509
- Accepts only number values, but return their boolean representation.
510
-
511
- <!-- prettier-ignore-start -->
512
- ```javascript
513
- const verify = guard(numericBoolean);
514
-
515
- // 👍
516
- verify(-1) === true;
517
- verify(0) === false;
518
- verify(123) === true;
519
-
520
- // 👎
521
- verify(false); // throws
522
- verify(true); // throws
523
- verify(undefined); // throws
524
- verify('hello'); // throws
525
- ```
526
- <!-- prettier-ignore-end -->
527
-
528
- ---
529
-
530
- <a name="date" href="#date">#</a> <b>date</b>: <i>Decoder&lt;Date&gt;</i>
531
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/date.js 'Source')
532
-
533
- Accepts only JavaScript [Date][date-api] values.
534
-
535
- <!-- prettier-ignore-start -->
536
- ```javascript
537
- const verify = guard(date);
538
- const now = new Date();
539
-
540
- // 👍
541
- verify(now) === now;
542
-
543
- // 👎
544
- verify(123); // throws
545
- verify('hello'); // throws
546
- ```
547
- <!-- prettier-ignore-end -->
548
-
549
- ---
550
-
551
- <a name="iso8601" href="#iso8601">#</a> <b>iso8601</b>: <i>Decoder&lt;Date&gt;</i>
552
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/date.js 'Source')
553
-
554
- Accepts only [ISO8601][iso8601-fmt]-formatted strings. This is very useful for working
555
- with dates in APIs: serialize them as `.toISOString()` when sending, decode them with
556
- `iso8601` when receiving.
557
-
558
- **NOTE:** This decoder accepts _strings_, but returns _Date_ instances.
559
-
560
- <!-- prettier-ignore-start -->
561
- ```javascript
562
- const verify = guard(iso8601);
563
-
564
- // 👍
565
- verify('2020-06-01T12:00:00Z'); // ≈ new Date('2020-06-01T12:00:00Z')
566
-
567
- // 👎
568
- verify('2020-06-01'); // throws
569
- verify('hello'); // throws
570
- verify(123); // throws
571
- verify(new Date()); // throws (does not accept dates)
572
- ```
573
- <!-- prettier-ignore-end -->
574
-
575
- ---
576
-
577
- <a name="null_" href="#null_">#</a> <b>null\_</b>: <i>Decoder&lt;null&gt;</i>
578
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
579
-
580
- Accepts only the literal `null` value.
581
-
582
- <!-- prettier-ignore-start -->
583
- ```javascript
584
- const verify = guard(null_);
585
-
586
- // 👍
587
- verify(null) === null;
588
-
589
- // 👎
590
- verify(false); // throws
591
- verify(undefined); // throws
592
- verify('hello world'); // throws
593
- ```
594
- <!-- prettier-ignore-end -->
595
-
596
- ---
597
-
598
- <a name="undefined_" href="#undefined_">#</a> <b>undefined\_</b>:
599
- <i>Decoder&lt;undefined&gt;</i>
600
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
601
-
602
- Accepts only the literal `undefined` value.
603
-
604
- <!-- prettier-ignore-start -->
605
- ```javascript
606
- const verify = guard(undefined_);
607
-
608
- // 👍
609
- verify(undefined) === undefined;
610
-
611
- // 👎
612
- verify(null); // throws
613
- verify(false); // throws
614
- verify('hello world'); // throws
615
- ```
616
- <!-- prettier-ignore-end -->
617
-
618
- ---
619
-
620
- <a name="constant" href="#constant">#</a> <b>constant</b><i>&lt;T&gt;</i>(value: T):
621
- <i>Decoder&lt;T&gt;</i>
622
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
623
-
624
- Accepts only the given constant value.
625
-
626
- For TypeScript, use this syntax:
627
-
628
- ```typescript
629
- constant('something' as const);
630
- constant(42 as const);
631
- ```
632
-
633
- For Flow, use this syntax:
634
-
635
- ```javascript
636
- constant(('something': 'something'));
637
- constant((42: 42));
638
- ```
639
-
640
- Example:
641
-
642
- <!-- prettier-ignore-start -->
643
- ```typescript
644
- const verify = guard(constant('hello' as const));
645
-
646
- // 👍
647
- verify('hello') === 'hello';
648
-
649
- // 👎
650
- verify('this breaks'); // throws
651
- verify(false); // throws
652
- verify(undefined); // throws
653
- ```
654
- <!-- prettier-ignore-end -->
655
-
656
- ---
657
-
658
- <a name="hardcoded" href="#hardcoded">#</a> <b>hardcoded</b><i>&lt;T&gt;</i>(value: T):
659
- <i>Decoder&lt;T&gt;</i>
660
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
661
-
662
- Accepts any input, completely ignores it, and always returns the provided value. This is
663
- useful to manually add extra fields to object decoders.
664
-
665
- <!-- prettier-ignore-start -->
666
- ```javascript
667
- const verify = guard(hardcoded(42));
668
-
669
- // 👍
670
- verify('hello') === 42;
671
- verify(false) === 42;
672
- verify(undefined) === 42;
673
-
674
- // 👎
675
- // This decoder will never reject an input
676
- ```
677
- <!-- prettier-ignore-end -->
678
-
679
- ---
680
-
681
- <a name="fail" href="#fail">#</a> <b>fail</b>(): <i>Decoder&lt;empty&gt;</i>
682
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/fail.js 'Source')
683
-
684
- Rejects all inputs, and always fails with the given error message. May be useful for
685
- explicitly disallowing keys, or for testing purposes.
686
-
687
- <!-- prettier-ignore-start -->
688
- ```javascript
689
- const verify = guard(object({
690
- a: string,
691
- b: optional(fail('Key b has been removed')),
692
- }));
693
-
694
- // 👍
695
- verify({ a: 'foo' }); // ≈ { a: 'foo' };
696
- verify({ a: 'foo', c: 'bar' }); // ≈ { a: 'foo' };
697
-
698
- // 👎
699
- verify({ a: 'foo', b: 'bar' }); // throws
700
- ```
701
- <!-- prettier-ignore-end -->
702
-
703
- ---
704
-
705
- <a name="unknown" href="#unknown">#</a> <b>unknown</b>: <i>Decoder&lt;unknown&gt;</i>
706
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')
707
- <a name="mixed" href="#mixed">#</a> <b>mixed</b>: <i>Decoder&lt;mixed&gt;</i>
708
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/constants.js 'Source')<br />
709
-
710
- Accepts any value and returns it unchanged. Useful for situation in which you don't know
711
- or expect a specific type. Of course, the downside is that you won't know the type of the
712
- value statically and you'll have to further refine it yourself.
713
-
714
- ```javascript
715
- const verify = guard(mixed);
716
-
717
- // 👍
718
- verify('hello') === 'hello';
719
- verify(false) === false;
720
- verify(undefined) === undefined;
721
- verify([1, 2]) === [1, 2];
722
-
723
- // 👎
724
- // This decoder will never reject an input
725
- ```
726
-
727
- ### Compositions
728
-
729
- Composite decoders can build new decoders from existing decoders that can already decode a
730
- "subtype". Examples are: if you already have a `string` decoder (of type
731
- `Decoder<string>`), then you can use `array(string)` to automatically build a decoder for
732
- arrays of strings, which will be of type `Decoder<Array<string>>`.
733
-
734
- <a name="optional" href="#optional">#</a>
735
- <b>optional</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T |
736
- undefined&gt;</i>
737
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
738
-
739
- Accepts only the literal value `undefined`, or whatever the given decoder accepts.
740
-
741
- <!-- prettier-ignore-start -->
742
- ```javascript
743
- const verify = guard(optional(string));
744
-
745
- // 👍
746
- verify('hello') === 'hello';
747
- verify(undefined) === undefined;
748
-
749
- // 👎
750
- verify(null); // throws
751
- verify(0); // throws
752
- verify(42); // throws
753
- ```
754
- <!-- prettier-ignore-end -->
755
-
756
- 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
+ };
757
34
 
758
- ```javascript
759
- object({
35
+ //
36
+ // Write the decoder (= what you expect the data to look like)
37
+ //
38
+ const userDecoder = object({
760
39
  id: number,
761
40
  name: string,
762
- address: optional(string),
763
- });
764
- ```
765
-
766
- Which will decode to type:
767
-
768
- ```javascript
769
- {
770
- id: number,
771
- name: string,
772
- address?: string,
773
- }
774
- ```
775
-
776
- ---
777
-
778
- <a name="nullable" href="#nullable">#</a>
779
- <b>nullable</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T | null&gt;</i>
780
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
781
-
782
- Accepts only the literal value `null`, or whatever the given decoder accepts.
783
-
784
- <!-- prettier-ignore-start -->
785
- ```javascript
786
- const verify = guard(nullable(string));
787
-
788
- // 👍
789
- verify('hello') === 'hello';
790
- verify(null) === null;
791
-
792
- // 👎
793
- verify(undefined); // throws
794
- verify(0); // throws
795
- verify(42); // throws
796
- ```
797
- <!-- prettier-ignore-end -->
798
-
799
- ---
800
-
801
- <a name="maybe" href="#maybe">#</a> <b>maybe</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
802
- <i>Decoder&lt;?T&gt;</i>
803
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/optional.js 'Source')
804
-
805
- Accepts only `undefined`, `null`, or whatever the given decoder accepts.
806
-
807
- <!-- prettier-ignore-start -->
808
- ```javascript
809
- const verify = guard(maybe(string));
810
-
811
- // 👍
812
- verify('hello') === 'hello';
813
- verify(null) === null;
814
- verify(undefined) === undefined;
815
-
816
- // 👎
817
- verify(0); // throws
818
- verify(42); // throws
819
- ```
820
- <!-- prettier-ignore-end -->
821
-
822
- ---
823
-
824
- <a name="array" href="#array">#</a> <b>array</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
825
- <i>Decoder&lt;Array&lt;T&gt;&gt;</i>
826
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
827
-
828
- Accepts only arrays of whatever the given decoder accepts.
829
-
830
- <!-- prettier-ignore-start -->
831
- ```javascript
832
- const verify = guard(array(string));
833
-
834
- // 👍
835
- verify(['hello', 'world']) === ['hello', 'world'];
836
-
837
- // 👎
838
- verify(['hello', 1.2]); // throws
839
- ```
840
- <!-- prettier-ignore-end -->
841
-
842
- ---
843
-
844
- <a name="nonEmptyArray" href="#nonEmptyArray">#</a>
845
- <b>nonEmptyArray</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
846
- <i>Decoder&lt;Array&lt;T&gt;&gt;</i>
847
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
848
-
849
- Like `array()`, but will reject arrays with 0 elements.
850
-
851
- <!-- prettier-ignore-start -->
852
- ```javascript
853
- const verify = guard(nonEmptyArray(string));
854
-
855
- // 👍
856
- verify(['hello', 'world']) === ['hello', 'world'];
857
-
858
- // 👎
859
- verify(['hello', 1.2]); // throws
860
- verify([]); // throws
861
- ```
862
- <!-- prettier-ignore-end -->
863
-
864
- ---
865
-
866
- <a name="poja" href="#poja">#</a> <b>poja</b>: <i>Decoder&lt;Array&lt;unknown&gt;&gt;</i>
867
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
868
-
869
- Accepts any array, but doesn't validate its items further.
870
-
871
- "poja" means "plain old JavaScript array", a play on ["pojo"](#pojo).
872
-
873
- <!-- prettier-ignore-start -->
874
- ```javascript
875
- const verify = guard(poja);
876
-
877
- // 👍
878
- verify([1, 'hi', true]) === [1, 'hi', true];
879
- verify(['hello', 'world']) === ['hello', 'world'];
880
- verify([]) === [];
881
-
882
- // 👎
883
- verify({}); // throws
884
- verify('hi'); // throws
885
- ```
886
- <!-- prettier-ignore-end -->
887
-
888
- ---
889
-
890
- <a name="tuple" href="#tuple">#</a> <b>tuple</b><i>&lt;A, B, C,
891
- ...&gt;</i>(<i>Decoder&lt;A&gt;</i>, <i>Decoder&lt;B&gt;</i>, <i>Decoder&lt;C&gt;</i>):
892
- <i>Decoder&lt;[A, B, C, ...]&gt;</i>
893
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/tuple.js 'Source')
894
-
895
- Accepts a tuple (an array with exactly _n_ items) of values accepted by the _n_ given
896
- decoders.
897
-
898
- <!-- prettier-ignore-start -->
899
- ```javascript
900
- const verify = guard(tuple(string, number));
901
-
902
- // 👍
903
- verify(['hello', 1.2]) === ['hello', 1.2];
904
-
905
- // 👎
906
- verify([]); // throws, too few items
907
- verify(['hello', 'world']); // throws, not the right types
908
- verify(['a', 1, 'c']); // throws, too many items
909
- ```
910
- <!-- prettier-ignore-end -->
911
-
912
- ---
913
-
914
- <a name="set" href="#set">#</a> <b>set</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
915
- <i>Decoder&lt;Set&lt;T&gt;&gt;</i>
916
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/array.js 'Source')
917
-
918
- Similar to [`array`](#array), but returns the result as an ES6 Set.
919
-
920
- <!-- prettier-ignore-start -->
921
- ```javascript
922
- const verify = guard(set(string));
923
-
924
- // 👍
925
- verify(['hello', 'world']) // ≈ new Set(['hello', 'world']);
926
-
927
- // 👎
928
- verify(['hello', 1.2]); // throws
929
- ```
930
- <!-- prettier-ignore-end -->
931
-
932
- ---
933
-
934
- <a name="object" href="#object">#</a> <b>object</b><i>&lt;O: { [field: string]:
935
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
936
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
937
-
938
- Accepts object values with fields matching the given decoders. Extra fields that exist on
939
- the input object are ignored and will not be returned.
940
-
941
- <!-- prettier-ignore-start -->
942
- ```javascript
943
- const verify = guard(
944
- object({
945
- x: number,
946
- y: number,
947
- }),
948
- );
949
-
950
- // 👍
951
- verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
952
- verify({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2 }; // ⚠️ extra field `z` not returned!
953
-
954
- // 👎
955
- verify({ x: 1 }); // throws, missing field `y`
956
- ```
957
- <!-- prettier-ignore-end -->
958
-
959
- For more information, see also
960
- [The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
961
-
962
- ---
963
-
964
- <a name="exact" href="#exact">#</a> <b>exact</b><i>&lt;O: { [field: string]:
965
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
966
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
967
-
968
- Like `object()`, but will reject inputs that contain extra keys that are not specified
969
- explicitly.
970
-
971
- <!-- prettier-ignore-start -->
972
- ```javascript
973
- const verify = guard(
974
- exact({
975
- x: number,
976
- y: number,
977
- }),
978
- );
979
-
980
- // 👍
981
- verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
982
-
983
- // 👎
984
- verify({ x: 1, y: 2, z: 3 }); // throws, extra field `z` not allowed
985
- verify({ x: 1 }); // throws, missing field `y`
986
- ```
987
- <!-- prettier-ignore-end -->
988
-
989
- For more information, see also
990
- [The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
991
-
992
- ---
993
-
994
- <a name="inexact" href="#inexact">#</a> <b>inexact</b><i>&lt;O: { [field: string]:
995
- Decoder&lt;any&gt; }&gt;</i>(mapping: O): <i>Decoder&lt;{ ... }&gt;</i>
996
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
997
-
998
- Like `object()`, but will pass through any extra fields on the input object unvalidated
999
- that will thus be of `unknown` type statically.
1000
-
1001
- <!-- prettier-ignore-start -->
1002
- ```javascript
1003
- const verify = guard(
1004
- inexact({
1005
- x: number,
1006
- }),
1007
- );
1008
-
1009
- // 👍
1010
- verify({ x: 1, y: 2 }) === { x: 1, y: 2 };
1011
- verify({ x: 1, y: 2, z: 3 }) === { x: 1, y: 2, z: 3 };
1012
-
1013
- // 👎
1014
- verify({ x: 1 }); // throws, missing field `y`
1015
- ```
1016
- <!-- prettier-ignore-end -->
1017
-
1018
- For more information, see also
1019
- [The difference between `object`, `exact`, and `inexact`](#the-difference-between-object-exact-and-inexact).
1020
-
1021
- ---
1022
-
1023
- <a name="pojo" href="#pojo">#</a> <b>pojo</b>: <i>Decoder&lt;{ [key: string]: unknown
1024
- }&gt;</i>
1025
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
1026
-
1027
- Accepts any "plain old JavaScript object", but doesn't validate its keys or values
1028
- further.
1029
-
1030
- <!-- prettier-ignore-start -->
1031
- ```javascript
1032
- const verify = guard(pojo);
1033
-
1034
- // 👍
1035
- verify({}) === {};
1036
- verify({ name: 'hi' }) === { name: 'hi' };
1037
-
1038
- // 👎
1039
- verify('hi'); // throws
1040
- verify([]); // throws
1041
- verify(new Date()); // throws
1042
- verify(null); // throws
1043
- ```
1044
- <!-- prettier-ignore-end -->
1045
-
1046
- ---
1047
-
1048
- <a name="dict" href="#dict">#</a> <b>dict</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>):
1049
- <i>Decoder&lt;{ [string]: &lt;T&gt;}&gt;</i>
1050
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
1051
-
1052
- Accepts objects where all values match the given decoder, and returns the result as a
1053
- `{ [string]: T }`.
1054
-
1055
- The main difference between `object()` and `dict()` is that you'd typically use `object()`
1056
- if this is a record-like object, where all field names are known and the values are
1057
- heterogeneous. Whereas with `dict()` the keys are typically dynamic and the values
1058
- homogeneous, like in a dictionary, a lookup table, or a cache.
1059
-
1060
- ```javascript
1061
- const verify = guard(dict(person)); // Assume you have a "person" decoder already
1062
-
1063
- // 👍
1064
- verify({
1065
- 1: { name: 'Alice' },
1066
- 2: { name: 'Bob' },
1067
- 3: { name: 'Charlie' },
1068
- }); // ≈ {
1069
- // "1": { name: "Alice" },
1070
- // "2": { name: "Bob" },
1071
- // "3": { name: "Charlie" },
1072
- // }
1073
- ```
1074
-
1075
- ---
1076
-
1077
- <a name="mapping" href="#mapping">#</a>
1078
- <b>mapping</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;Map&lt;string,
1079
- T&gt;&gt;</i>
1080
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/object.js 'Source')
1081
-
1082
- Like `dict()`, but returns the result as a `Map<string, T>` instead.
1083
-
1084
- ```javascript
1085
- const verify = guard(mapping(person)); // Assume you have a "person" decoder already
1086
-
1087
- // 👍
1088
- verify({
1089
- 1: { name: 'Alice' },
1090
- 2: { name: 'Bob' },
1091
- 3: { name: 'Charlie' },
1092
- });
1093
- // ≈ Map([
1094
- // ['1', { name: 'Alice' }],
1095
- // ['2', { name: 'Bob' }],
1096
- // ['3', { name: 'Charlie' }],
1097
- // ]);
1098
- ```
1099
-
1100
- ---
1101
-
1102
- <a name="json" href="#json">#</a> <b>json</b>: <i>Decoder&lt;JSONValue&gt;</i>
1103
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
1104
-
1105
- Accepts any value that's a valid JSON value:
1106
-
1107
- - `null`
1108
- - `string`
1109
- - `number`
1110
- - `boolean`
1111
- - `{ [string]: JSONValue }`
1112
- - `Array<JSONValue>`
1113
-
1114
- ```javascript
1115
- const verify = guard(json);
1116
-
1117
- // 👍
1118
- verify({
1119
- name: 'Amir',
1120
- age: 27,
1121
- admin: true,
1122
- image: null,
1123
- tags: ['vip', 'staff'],
41
+ createdAt: optional(iso8601),
42
+ tags: array(string),
1124
43
  });
1125
- ```
1126
-
1127
- Any value returned by `JSON.parse()` should decode without failure.
1128
-
1129
- ---
1130
-
1131
- <a name="jsonObject" href="#jsonObject">#</a> <b>jsonObject</b>:
1132
- <i>Decoder&lt;JSONObject&gt;</i>
1133
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
1134
-
1135
- Like `json`, but will only decode when the JSON value is an object.
1136
-
1137
- <!-- prettier-ignore-start -->
1138
- ```javascript
1139
- const verify = guard(json);
1140
-
1141
- // 👍
1142
- verify({}); // ≈ {}
1143
- verify({ name: 'Amir' }); // ≈ { name: 'Amir' }
1144
-
1145
- // 👎
1146
- verify([]); // throws
1147
- verify([{ name: 'Alice' }]); // throws
1148
- verify('hello'); // throws
1149
- verify(null); // throws
1150
- ```
1151
- <!-- prettier-ignore-end -->
1152
-
1153
- ---
1154
-
1155
- <a name="jsonArray" href="#jsonArray">#</a> <b>jsonArray</b>:
1156
- <i>Decoder&lt;JSONArray&gt;</i>
1157
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/json.js 'Source')
1158
-
1159
- Like `json`, but will only decode when the JSON value is an array.
1160
-
1161
- <!-- prettier-ignore-start -->
1162
- ```javascript
1163
- const verify = guard(json);
1164
-
1165
- // 👍
1166
- verify([]); // ≈ []
1167
- verify([{ name: 'Amir' }]); // ≈ [{ name: 'Amir' }]
1168
-
1169
- // 👎
1170
- verify({}); // throws
1171
- verify({ name: 'Alice' }); // throws
1172
- verify('hello'); // throws
1173
- verify(null); // throws
1174
- ```
1175
- <!-- prettier-ignore-end -->
1176
-
1177
- ---
1178
-
1179
- <a name="either" href="#either">#</a> <b>either</b><i>&lt;A, B, C,
1180
- ...&gt;</i>(<i>Decoder&lt;A&gt;</i>, <i>Decoder&lt;B&gt;</i>, <i>Decoder&lt;C&gt;</i>,
1181
- ...): <i>Decoder&lt;A | B | C | ...&gt;</i><br />
1182
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/either.js 'Source')<br />
1183
-
1184
- Accepts any value that is accepted by any of the given decoders. The decoders are
1185
- attempted on the input in given order. The first one that accepts the input "wins".
1186
-
1187
- <!-- prettier-ignore-start -->
1188
- ```javascript
1189
- const verify = guard(either(number, string));
1190
-
1191
- // 👍
1192
- verify('hello world') === 'hello world';
1193
- verify(123) === 123;
1194
-
1195
- // 👎
1196
- verify(false); // throws
1197
- ```
1198
- <!-- prettier-ignore-end -->
1199
-
1200
- **NOTE to Flow users:** In Flow, there is a max of 16 arguments with this construct. (This
1201
- is no problem in TypeScript.) If you hit the 16 argument limit, you can work around that
1202
- by stacking, e.g. do `either(<15 arguments here>, either(...))`.
1203
-
1204
- ---
1205
-
1206
- <a name="taggedUnion" href="#taggedUnion">#</a> <b>taggedUnion</b><i>&lt;O: { [field:
1207
- string]: (Decoder&lt;T&gt; | Decoder&lt;V&gt; | ...) }&gt;</i>(field: string, mapping: O):
1208
- <i>Decoder&lt;T | V | ...&gt;</i>
1209
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/dispatch.js 'Source')
1210
-
1211
- **NOTE:** In decoders@1.x, this was called `dispatch()`.
1212
-
1213
- Like `either`, but only for building unions of object types with a common field (like a
1214
- `type` field) that lets you distinguish members.
1215
-
1216
- The following two decoders are effectively equivalent:
1217
-
1218
- ```javascript
1219
- type Rect = { __type: 'rect', x: number, y: number, width: number, height: number };
1220
- type Circle = { __type: 'circle', cx: number, cy: number, r: number };
1221
- // ^^^^^^
1222
- // Field that defines which decoder to pick
1223
- // vvvvvv
1224
- const shape1: Decoder<Rect | Circle> = taggedUnion('__type', { rect, circle });
1225
- const shape2: Decoder<Rect | Circle> = either(rect, circle);
1226
- ```
1227
-
1228
- But using `taggedUnion()` will typically be more runtime-efficient than using `either()`.
1229
- The reason is that `taggedUnion()` will first do minimal work to "look ahead" into the
1230
- `type` field here, and based on that value, pick which decoder to invoke. Error messages
1231
- will then also be tailored to the specific decoder.
1232
-
1233
- The `either()` version will instead try each decoder in turn until it finds one that
1234
- matches. If none of the alternatives match, it needs to report all errors, which is
1235
- sometimes confusing.
1236
-
1237
- ---
1238
-
1239
- <a name="oneOf" href="#oneOf">#</a> <b>oneOf</b><i>&lt;T&gt;</i>(<i>Array&lt;T&gt;</i>):
1240
- <i>Decoder&lt;T&gt;</i>
1241
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/either.js 'Source')<br />
1242
-
1243
- Accepts any value that is strictly-equal (using `===`) to one of the specified values.
1244
-
1245
- <!-- prettier-ignore-start -->
1246
- ```javascript
1247
- const verify = guard(oneOf(['foo', 'bar', 3]));
1248
-
1249
- // 👍
1250
- verify('foo') === 'foo';
1251
- verify(3) === 3;
1252
-
1253
- // 👎
1254
- verify('hello'); // throws
1255
- verify(4); // throws
1256
- verify(false); // throws
1257
- ```
1258
- <!-- prettier-ignore-end -->
1259
-
1260
- For example, given an array of strings, like so:
1261
-
1262
- ```javascript
1263
- oneOf(['foo', 'bar']);
1264
- ```
1265
-
1266
- TypeScript is capable of inferring the return type as `Decoder<'foo' | 'bar'>`, but in
1267
- Flow it will (unfortunately) be `Decoder<string>`. So in Flow, be sure to explicitly
1268
- annotate the type. Either by doing `oneOf([('foo': 'foo'), ('bar': 'bar')])`, or as
1269
- `oneOf<'foo' | 'bar'>(['foo', 'bar'])`.
1270
-
1271
- ---
1272
-
1273
- <a name="instanceOf" href="#instanceOf">#</a>
1274
- <b>instanceOf</b><i>&lt;T&gt;</i>(<i>Class&lt;T&gt;</i>): <i>Decoder&lt;T&gt;</i>
1275
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/instanceOf.js 'Source')<br />
1276
-
1277
- Accepts any value that is an `instanceof` the given class.
1278
-
1279
- > **NOTE: Help wanted!** The TypeScript annotation for this decoder needs help! If you
1280
- > know how to express it, please submit a PR. See
1281
- > https://github.com/nvie/decoders/blob/main/src/core/instanceOf.d.ts
1282
-
1283
- <!-- prettier-ignore-start -->
1284
- ```javascript
1285
- const verify = guard(instanceOf(Error));
1286
-
1287
- // 👍
1288
- const value = new Error('foo');
1289
- verify(value) === value;
1290
-
1291
- // 👎
1292
- verify('foo'); // throws
1293
- verify(3); // throws
1294
- ```
1295
- <!-- prettier-ignore-end -->
1296
-
1297
- ---
1298
-
1299
- <a name="transform" href="#transform">#</a> <b>transform</b><i>&lt;T,
1300
- V&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>&lt;T&gt;</i> =&gt; <i>&lt;V&gt;</i>):
1301
- <i>Decoder&lt;V&gt;</i>
1302
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/utils.js 'Source')<br />
1303
-
1304
- Accepts any value the given decoder accepts, and on success, will call the mapper value
1305
- **on the decoded result**. If the mapper function throws an error, the whole decoder will
1306
- fail using the error message as the failure reason.
1307
-
1308
- <!-- prettier-ignore-start -->
1309
- ```javascript
1310
- const upper = transform(string, (s) => s.toUpperCase());
1311
- const verify = guard(upper);
1312
-
1313
- // 👍
1314
- verify('foo') === 'FOO';
1315
-
1316
- // 👎
1317
- verify(4); // throws
1318
- ```
1319
- <!-- prettier-ignore-end -->
1320
-
1321
- ---
1322
-
1323
- <a name="compose" href="#compose">#</a> <b>compose</b><i>&lt;T,
1324
- V&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>Decoder&lt;V, T&gt;</i>): <i>Decoder&lt;V&gt;</i>
1325
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
1326
-
1327
- Given a decoder for _T_ and another one for _V_-given-a-_T_. Will first decode the input
1328
- using the first decoder, and _if okay_, pass the result on to the second decoder. The
1329
- second decoder will thus be able to make more assumptions about its input value, i.e. it
1330
- can know what type the input value is (`T` instead of `unknown`).
1331
-
1332
- This is an advanced decoder, typically only useful for authors of decoders. It's not
1333
- recommended to rely on this decoder directly for normal usage.
1334
-
1335
- ---
1336
-
1337
- <a name="predicate" href="#predicate">#</a>
1338
- <b>predicate</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>&lt;T&gt; => boolean</i>,
1339
- string): <i>Decoder&lt;T&gt;</i>
1340
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
1341
-
1342
- Accepts values that are accepted by the decoder _and_ also pass the predicate function.
1343
-
1344
- <!-- prettier-ignore-start -->
1345
- ```typescript
1346
- const odd = predicate(
1347
- number,
1348
- (n) => n % 2 !== 0,
1349
- 'Must be odd'
1350
- );
1351
- const verify = guard(odd);
1352
-
1353
- // 👍
1354
- verify(3) === 3;
1355
-
1356
- // 👎
1357
- verify('hi'); // throws: not a number
1358
- verify(42); // throws: not an odd number
1359
- ```
1360
- <!-- prettier-ignore-end -->
1361
-
1362
- In TypeScript, if you provide a predicate that also doubles as a [type
1363
- predicate][type-predicates], then this will be reflected in the return type, too.
1364
-
1365
- ---
1366
-
1367
- <a name="prep" href="#prep">#</a> <b>prep</b><i>&lt;T, I&gt;</i>(<i>unknown => I</i>,
1368
- <i>Decoder&lt;T, I&gt;</i>): <i>Decoder&lt;T&gt;</i>
1369
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/composition.js 'Source')<br />
1370
-
1371
- Pre-process the raw data input before passing it into the decoder. This gives you the
1372
- ability to arbitrarily customize the input on the fly before passing it to the decoder. Of
1373
- course, the input value at that point is still of `unknown` type, so you will have to deal
1374
- with that accordingly.
1375
-
1376
- <!-- prettier-ignore-start -->
1377
- ```typescript
1378
- const verify = prep(
1379
- // Will convert any input to an int first, before feeding it to
1380
- // positiveInteger. This will effectively also allow numeric strings
1381
- // to be accepted (and returned) as integers. If this ever throws,
1382
- // then the error message will be what gets annotated on the input.
1383
- x => parseInt(x),
1384
- positiveInteger,
1385
- );
1386
-
1387
- // 👍
1388
- verify(42) === 42;
1389
- verify('3') === 3;
1390
-
1391
- // 👎
1392
- verify('-3'); // throws: not a positive number
1393
- verify('hi'); // throws: not a number
1394
- ```
1395
- <!-- prettier-ignore-end -->
1396
-
1397
- ---
1398
-
1399
- <a name="describe" href="#describe">#</a>
1400
- <b>describe</b><i>&lt;T&gt;</i>(<i>Decoder&lt;T&gt;</i>, <i>string</i>):
1401
- <i>Decoder&lt;T&gt;</i>
1402
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/describe.js 'Source')<br />
1403
-
1404
- Uses the given decoder, but will use an alternative error message in case it rejects. This
1405
- can be used to simplify or shorten otherwise long or low-level/technical errors.
1406
-
1407
- ```javascript
1408
- const vowel = describe(
1409
- either5(constant('a'), constant('e'), constant('i'), constant('o'), constant('u')),
1410
- 'Must be vowel',
1411
- );
1412
- ```
1413
-
1414
- ---
1415
-
1416
- <a name="lazy" href="#lazy">#</a> <b>lazy</b><i>&lt;T&gt;</i>(() =>
1417
- <i>Decoder&lt;T&gt;</i>): <i>Decoder&lt;T&gt;</i>
1418
- [&lt;&gt;](https://github.com/nvie/decoders/blob/main/src/core/lazy.js 'Source')<br />
1419
-
1420
- Lazily evaluate the given decoder. This is useful to build self-referential types for
1421
- recursive data structures. Example:
1422
-
1423
- ```js
1424
- type Tree = {
1425
- value: string,
1426
- children: Array<Tree>,
1427
- // ^^^^
1428
- // Self-reference defining a recursive type
1429
- };
1430
-
1431
- const treeDecoder: Decoder<Tree> = object({
1432
- value: string,
1433
- children: array(lazy(() => treeDecoder)),
1434
- // ^^^^^^^^^^^^^^^^^^^^^^^
1435
- // Use lazy() like this to refer to the treeDecoder which is
1436
- // getting defined here
1437
- });
1438
- ```
1439
-
1440
- ### The difference between `object`, `exact`, and `inexact`
1441
-
1442
- The three decoders in the "object" family of decoders only differ in how they treat extra
1443
- properties on input values.
1444
-
1445
- For example, for a definition like:
1446
-
1447
- ```js
1448
- import { exact, inexact, number, object, string } from 'decoders';
1449
-
1450
- const thing = {
1451
- a: string,
1452
- b: number,
1453
- };
1454
- ```
1455
-
1456
- And a runtime input of:
1457
-
1458
- ```js
1459
- {
1460
- a: "hi",
1461
- b: 42,
1462
- c: "extra", // Note "c" is not a known field
1463
- }
1464
- ```
1465
-
1466
- | | Extra properties | Output value | Inferred type |
1467
- | ---------------- | ---------------- | ------------------------------ | ------------------------------------------- |
1468
- | `object(thing)` | discarded | `{a: "hi", b: 42}` | `{a: string, b: number}` |
1469
- | `exact(thing)` | not allowed | n/a (rejected) | `{a: string, b: number}` |
1470
- | `inexact(thing)` | retained | `{a: "hi", b: 42, c: "extra"}` | `{a: string, b: number, [string]: unknown}` |
1471
-
1472
- ### Building custom decoders
1473
-
1474
- There are two main building blocks for defining your own custom decoders: `transform()`
1475
- and `compose()`.
1476
-
1477
- There are roughly 3 use cases that you will want to use:
1478
-
1479
- 1. **[Transformation](#transformation)** (i.e. read one type, but return another, or read
1480
- a type but change its value before returning)
1481
- 1. **[Adding extra value requirements](#adding-predicates)** (i.e. decode using an
1482
- existing decoder, but require an extra value check)
1483
- 1. **Chaining** multiple decoders (less common, more advanced)
1484
-
1485
- #### Transformation
1486
-
1487
- To read one type from the input, but return another, use:
1488
-
1489
- ```js
1490
- const numericString: Decoder<number> = transform(
1491
- // At runtime, expect to read a string...
1492
- string,
1493
- // ...but return it as a number
1494
- (s) => Number(s),
1495
- );
1496
- ```
1497
-
1498
- To read one type, but change its value before returning:
1499
-
1500
- ```js
1501
- const upperCase: Decoder<string> = transform(string, (s) => s.toUpperCase());
1502
- ```
1503
-
1504
- **WARNING:** While you can map anything to anything, it's typically **NOT A GOOD IDEA to
1505
- put too much transformation logic inside decoders**. It's recommended to keep them minimal
1506
- and only try to use them for the most basic use cases, like in the examples above. Keeping
1507
- business logic outside decoders makes them more reusable and composable.
1508
-
1509
- #### Adding predicates
1510
-
1511
- The easiest way to decode using an existing decoder, but enforcing extra runtime checks on
1512
- their values is by wrapping it in a `predicate(...)` construction:
1513
-
1514
- ```js
1515
- const odd = predicate(integer, (n) => n % 2 !== 0, 'Must be odd');
1516
- const shortString = predicate(string, (s) => s.length < 8, 'Must be less than 8 chars');
1517
- ```
1518
44
 
1519
- [date-api]:
1520
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
1521
- [iso8601-fmt]: https://en.wikipedia.org/wiki/ISO_8601
1522
- [type-predicates]:
1523
- https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
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 can be found on [https://decoders.cc](https://decoders.cc).
137
+ (Old v1 documentation can still be found
138
+ [here](https://github.com/nvie/decoders/tree/v1.25.5#readme).)