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