zod 3.22.4 → 3.23.8
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/README.md +279 -237
- package/lib/ZodError.d.ts +2 -1
- package/lib/ZodError.js +5 -0
- package/lib/benchmarks/datetime.d.ts +5 -0
- package/lib/benchmarks/datetime.js +54 -0
- package/lib/benchmarks/index.js +15 -2
- package/lib/benchmarks/ipv4.d.ts +5 -0
- package/lib/benchmarks/ipv4.js +54 -0
- package/lib/benchmarks/primitives.js +34 -0
- package/lib/helpers/parseUtil.d.ts +1 -1
- package/lib/helpers/parseUtil.js +15 -5
- package/lib/helpers/util.d.ts +16 -2
- package/lib/index.mjs +289 -70
- package/lib/index.umd.js +289 -69
- package/lib/types.d.ts +113 -43
- package/lib/types.js +249 -67
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
<br/>
|
|
38
38
|
<br/>
|
|
39
39
|
|
|
40
|
+
> Zod 3.23 is out! View the [release notes](https://github.com/colinhacks/zod/releases/tag/v3.23.0).
|
|
41
|
+
|
|
40
42
|
> These docs have been translated into [Chinese](./README_ZH.md).
|
|
41
43
|
|
|
42
44
|
## Table of contents
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
- [Gold](#gold)
|
|
52
54
|
- [Silver](#silver)
|
|
53
55
|
- [Bronze](#bronze)
|
|
56
|
+
- [Copper](#copper)
|
|
54
57
|
- [Ecosystem](#ecosystem)
|
|
55
58
|
- [Resources](#resources)
|
|
56
59
|
- [API libraries](#api-libraries)
|
|
@@ -69,7 +72,9 @@
|
|
|
69
72
|
- [Coercion for primitives](#coercion-for-primitives)
|
|
70
73
|
- [Literals](#literals)
|
|
71
74
|
- [Strings](#strings)
|
|
72
|
-
- [
|
|
75
|
+
- [Datetimes](#datetimes)
|
|
76
|
+
- [Dates](#dates)
|
|
77
|
+
- [Times](#times)
|
|
73
78
|
- [IP addresses](#ip-addresses)
|
|
74
79
|
- [Numbers](#numbers)
|
|
75
80
|
- [BigInts](#bigints)
|
|
@@ -180,145 +185,132 @@ Some other great aspects:
|
|
|
180
185
|
|
|
181
186
|
Sponsorship at any level is appreciated and encouraged. For individual developers, consider the [Cup of Coffee tier](https://github.com/sponsors/colinhacks). If you built a paid product using Zod, consider one of the [podium tiers](https://github.com/sponsors/colinhacks).
|
|
182
187
|
|
|
183
|
-
####
|
|
188
|
+
#### Platinum
|
|
184
189
|
|
|
185
|
-
|
|
190
|
+
> [Email me](mailto:colin@colinhacks.com) to discuss sponsoring Zod at this level.
|
|
191
|
+
|
|
192
|
+
<!-- <table>
|
|
186
193
|
<tr>
|
|
187
194
|
<td align="center">
|
|
188
|
-
<a href="https://
|
|
189
|
-
<img src="https://
|
|
195
|
+
<a href="https://www.example.com" target="_blank">
|
|
196
|
+
<img src="https://example.com/image.png" height="100px;" alt="XXX" />
|
|
190
197
|
</a>
|
|
191
198
|
<br />
|
|
192
|
-
<b>
|
|
193
|
-
<br />
|
|
194
|
-
<a href="https://speakeasyapi.dev/">speakeasyapi.dev</a>
|
|
199
|
+
<b>XXX</b>
|
|
195
200
|
<br />
|
|
196
|
-
<
|
|
201
|
+
<a href="https://www.example.com" target="_blank">example.com</a>
|
|
197
202
|
</td>
|
|
203
|
+
</tr>
|
|
204
|
+
</table> -->
|
|
205
|
+
|
|
206
|
+
#### Gold
|
|
207
|
+
|
|
208
|
+
<table>
|
|
209
|
+
<tr>
|
|
198
210
|
<td align="center">
|
|
199
|
-
<
|
|
200
|
-
<img src="https://i.imgur.com/R0R43S2.jpg" width="200px;" alt="Glow Wallet" />
|
|
201
|
-
</a>
|
|
211
|
+
<img src="https://avatars.githubusercontent.com/u/80861386?s=200&v=4" height="45px;" alt="Cerbos" />
|
|
202
212
|
<br />
|
|
203
|
-
<
|
|
213
|
+
<a href="https://cerbos.dev/" target="_blank">Cerbos</a>
|
|
214
|
+
</td>
|
|
215
|
+
<td align="center">
|
|
216
|
+
<img src="https://avatars.githubusercontent.com/u/301879?s=200&v=4" height="45px;" alt="Scalar.com logo" />
|
|
204
217
|
<br />
|
|
205
|
-
<a href="https://
|
|
218
|
+
<a href="https://scalar.com/" target="_blank">Scalar</a>
|
|
219
|
+
</td>
|
|
220
|
+
<td align="center">
|
|
221
|
+
<img src="https://avatars.githubusercontent.com/u/91446104?s=200&v=4" height="45px;" alt="Speakeasy API" />
|
|
206
222
|
<br />
|
|
207
|
-
<
|
|
208
|
-
<br/>
|
|
209
|
-
Solana wallet.</p>
|
|
223
|
+
<a href="https://speakeasyapi.dev/" target="_blank">Speakeasy</a>
|
|
210
224
|
</td>
|
|
211
|
-
</tr>
|
|
212
|
-
<tr>
|
|
213
225
|
<td align="center">
|
|
214
|
-
<
|
|
215
|
-
<img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="Deletype logo" />
|
|
216
|
-
</a>
|
|
226
|
+
<img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" height="45px;" alt="Deletype logo" />
|
|
217
227
|
<br />
|
|
218
|
-
<
|
|
228
|
+
<a href="https://deletype.com" target="_blank">Deletype</a>
|
|
229
|
+
</td>
|
|
230
|
+
<td align="center">
|
|
231
|
+
<img src="https://avatars.githubusercontent.com/u/95297378?s=200&v=4" height="45px;" alt="Trigger.dev logo" />
|
|
219
232
|
<br />
|
|
220
|
-
<a href="https://
|
|
233
|
+
<a href="https://trigger.dev" target="_blank">Trigger.dev</a>
|
|
221
234
|
</td>
|
|
235
|
+
</tr><tr>
|
|
222
236
|
<td align="center">
|
|
223
|
-
<
|
|
224
|
-
<img src="https://avatars.githubusercontent.com/u/95297378?s=200&v=4" width="200px;" alt="Trigger.dev logo" />
|
|
225
|
-
</a>
|
|
237
|
+
<img src="https://avatars.githubusercontent.com/u/125754?s=200&v=4" height="45px;" alt="Transloadit logo" />
|
|
226
238
|
<br />
|
|
227
|
-
<
|
|
239
|
+
<a href="https://transloadit.com/?utm_source=zod&utm_medium=refe
|
|
240
|
+
rral&utm_campaign=sponsorship&utm_content=github" target="_blank">Transloadit</a>
|
|
241
|
+
</td>
|
|
242
|
+
<td align="center">
|
|
243
|
+
<img src="https://avatars.githubusercontent.com/u/107880645?s=200&v=4" height="45px;" alt="Infisical logo" />
|
|
228
244
|
<br />
|
|
229
|
-
<a href="https://
|
|
230
|
-
<br/>
|
|
231
|
-
<p>Effortless automation for developers.</p>
|
|
245
|
+
<a href="https://infisical.com" target="_blank">Infisical</a>
|
|
232
246
|
</td>
|
|
233
|
-
</tr>
|
|
234
|
-
<tr>
|
|
235
247
|
<td align="center">
|
|
236
|
-
<
|
|
237
|
-
<img src="https://avatars.githubusercontent.com/u/125754?s=200&v=4" width="200px;" alt="Transloadit logo" />
|
|
238
|
-
</a>
|
|
248
|
+
<img src="https://avatars.githubusercontent.com/u/91036480?s=200&v=4" height="45px;" alt="Whop logo" />
|
|
239
249
|
<br />
|
|
240
|
-
<
|
|
250
|
+
<a href="https://whop.com/" target="_blank">Whop</a>
|
|
251
|
+
</td>
|
|
252
|
+
<td align="center">
|
|
253
|
+
<img src="https://avatars.githubusercontent.com/u/36402888?s=200&v=4" height="45px;" alt="CryptoJobsList logo" />
|
|
241
254
|
<br />
|
|
242
|
-
<a href="https://
|
|
243
|
-
<br/>
|
|
244
|
-
<p>Simple file processing for developers.</p>
|
|
255
|
+
<a href="https://cryptojobslist.com/" target="_blank">CryptoJobsList</a>
|
|
245
256
|
</td>
|
|
246
257
|
<td align="center">
|
|
247
|
-
<
|
|
248
|
-
<img src="https://avatars.githubusercontent.com/u/107880645?s=200&v=4" width="200px;" alt="Infisical logo" />
|
|
249
|
-
</a>
|
|
258
|
+
<img src="https://avatars.githubusercontent.com/u/70170949?s=200&v=4" height="45px;" alt="Plain logo" />
|
|
250
259
|
<br />
|
|
251
|
-
<
|
|
260
|
+
<a href="https://plain.com/" target="_blank">Plain.</a>
|
|
261
|
+
</td>
|
|
262
|
+
</tr><tr>
|
|
263
|
+
<td align="center">
|
|
264
|
+
<img src="https://avatars.githubusercontent.com/u/78935958?s=200&v=4" height="45px;" alt="Inngest logo" />
|
|
252
265
|
<br />
|
|
253
|
-
<a href="https://
|
|
254
|
-
<br/>
|
|
255
|
-
<p>Open-source platform for secret<br/>management: sync secrets across your<br/>team/infrastructure and prevent secret leaks.</p>
|
|
266
|
+
<a href="https://inngest.com/" target="_blank">Inngest</a>
|
|
256
267
|
</td>
|
|
257
|
-
</tr>
|
|
258
|
-
<tr>
|
|
259
268
|
<td align="center">
|
|
260
|
-
<
|
|
261
|
-
<img src="https://avatars.githubusercontent.com/u/91036480?s=200&v=4" width="200px;" alt="Whop logo" />
|
|
262
|
-
</a>
|
|
269
|
+
<img src="https://avatars.githubusercontent.com/u/13880908?s=200&v=4" height="45px;" alt="Storyblok CMS" />
|
|
263
270
|
<br />
|
|
264
|
-
<
|
|
271
|
+
<a href="https://storyblok.com/" target="_blank">Storyblok</a>
|
|
272
|
+
</td>
|
|
273
|
+
<td align="center">
|
|
274
|
+
<img src="https://avatars.githubusercontent.com/u/16199997?s=200&v=4" height="45px;" alt="Mux logo" />
|
|
265
275
|
<br />
|
|
266
|
-
<a href="https://
|
|
276
|
+
<a href="https://mux.link/zod" target="_blank">Mux</a>
|
|
277
|
+
</td>
|
|
278
|
+
<td align="center">
|
|
279
|
+
<img src="https://avatars.githubusercontent.com/u/180984?v=4" height="45px;" alt="@emreb" />
|
|
267
280
|
<br />
|
|
268
|
-
<
|
|
281
|
+
<a href="https://github.com/emreb" target="_blank"><code>@emreb</code></a>
|
|
269
282
|
</td>
|
|
283
|
+
</tr>
|
|
270
284
|
</table>
|
|
271
285
|
|
|
272
286
|
#### Silver
|
|
273
287
|
|
|
274
288
|
<table>
|
|
275
289
|
<tr>
|
|
276
|
-
<td align="center"
|
|
290
|
+
<td align="center">
|
|
277
291
|
<a href="https://www.numeric.io">
|
|
278
|
-
<img src="https://i.imgur.com/kTiLtZt.png"
|
|
292
|
+
<img src="https://i.imgur.com/kTiLtZt.png" height="40px;" alt="Numeric logo" />
|
|
279
293
|
</a>
|
|
280
|
-
<br />
|
|
281
|
-
<b>Numeric</b>
|
|
282
|
-
<br />
|
|
283
|
-
<a href="https://www.numeric.io">numeric.io</a>
|
|
284
294
|
</td>
|
|
285
|
-
<td
|
|
286
|
-
<a href="https://marcatopartners.com
|
|
287
|
-
<img src="https://avatars.githubusercontent.com/u/84106192?s=200&v=4"
|
|
295
|
+
<td>
|
|
296
|
+
<a href="https://marcatopartners.com">
|
|
297
|
+
<img src="https://avatars.githubusercontent.com/u/84106192?s=200&v=4" height="40px;" alt="Marcato Partners" />
|
|
288
298
|
</a>
|
|
289
|
-
<br />
|
|
290
|
-
<b>Marcato Partners</b>
|
|
291
|
-
<br />
|
|
292
|
-
<a href="https://marcatopartners.com/">marcatopartners.com</a>
|
|
293
299
|
</td>
|
|
294
|
-
|
|
295
|
-
<tr>
|
|
296
|
-
<td align="center">
|
|
300
|
+
<td>
|
|
297
301
|
<a href="https://interval.com">
|
|
298
|
-
<img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4"
|
|
302
|
+
<img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4" height="40px;" alt="" />
|
|
299
303
|
</a>
|
|
300
|
-
<br />
|
|
301
|
-
<b>Interval</b>
|
|
302
|
-
<br />
|
|
303
|
-
<a href="https://interval.com">interval.com</a>
|
|
304
304
|
</td>
|
|
305
|
-
<td
|
|
305
|
+
<td>
|
|
306
306
|
<a href="https://seasoned.cc">
|
|
307
|
-
<img src="https://avatars.githubusercontent.com/u/33913103?s=200&v=4"
|
|
307
|
+
<img src="https://avatars.githubusercontent.com/u/33913103?s=200&v=4" height="40px;" alt="" />
|
|
308
308
|
</a>
|
|
309
|
-
<br />
|
|
310
|
-
<b>Seasoned Software</b>
|
|
311
|
-
<br />
|
|
312
|
-
<a href="https://seasoned.cc">seasoned.cc</a>
|
|
313
309
|
</td>
|
|
314
|
-
<td
|
|
310
|
+
<td>
|
|
315
311
|
<a href="https://www.bamboocreative.nz/">
|
|
316
|
-
<img src="https://avatars.githubusercontent.com/u/41406870?v=4"
|
|
312
|
+
<img src="https://avatars.githubusercontent.com/u/41406870?v=4" height="40px;" alt="Bamboo Creative logo" />
|
|
317
313
|
</a>
|
|
318
|
-
<br />
|
|
319
|
-
<b>Bamboo Creative</b>
|
|
320
|
-
<br />
|
|
321
|
-
<a href="https://www.bamboocreative.nz">bamboocreative.nz</a>
|
|
322
314
|
</td>
|
|
323
315
|
</tr>
|
|
324
316
|
</table>
|
|
@@ -327,101 +319,31 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
327
319
|
|
|
328
320
|
<table>
|
|
329
321
|
<tr>
|
|
330
|
-
<td
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
<br />
|
|
335
|
-
<b>Brandon Bayer</b>
|
|
336
|
-
<br/>
|
|
337
|
-
<a href="https://twitter.com/flybayer">@flybayer</a>,
|
|
338
|
-
<span>creator of <a href="https://blitzjs.com">Blitz.js</a></span>
|
|
339
|
-
<br />
|
|
340
|
-
</td>
|
|
341
|
-
<td align="center">
|
|
342
|
-
<a href="https://github.com/brabeji">
|
|
343
|
-
<img src="https://avatars.githubusercontent.com/u/2237954?v=4" width="100px;" alt=""/>
|
|
344
|
-
</a>
|
|
345
|
-
<br />
|
|
346
|
-
<b>Jiří Brabec</b>
|
|
347
|
-
<br/>
|
|
348
|
-
<a href="https://github.com/brabeji">@brabeji</a>
|
|
349
|
-
<br />
|
|
350
|
-
</td>
|
|
351
|
-
<td align="center">
|
|
352
|
-
<a href="https://twitter.com/alexdotjs">
|
|
353
|
-
<img src="https://avatars.githubusercontent.com/u/459267?v=4" width="100px;" alt="" />
|
|
354
|
-
</a>
|
|
355
|
-
<br />
|
|
356
|
-
<b>Alex Johansson</b>
|
|
357
|
-
<br />
|
|
358
|
-
<a href="https://twitter.com/alexdotjs">@alexdotjs</a>
|
|
359
|
-
</td>
|
|
322
|
+
<td>Brandon Bayer</td>
|
|
323
|
+
<td>Jiří Brabec</td>
|
|
324
|
+
<td>Alex Johansson</td>
|
|
325
|
+
<td>Fungible Systems</td>
|
|
360
326
|
</tr>
|
|
361
327
|
<tr>
|
|
362
|
-
<td
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
<br />
|
|
367
|
-
<b>Fungible Systems</b>
|
|
368
|
-
<br/>
|
|
369
|
-
<a href="https://fungible.systems/">fungible.systems</a>
|
|
370
|
-
<br />
|
|
371
|
-
</td>
|
|
372
|
-
<td align="center">
|
|
373
|
-
<a href="https://adaptable.io/">
|
|
374
|
-
<img src="https://avatars.githubusercontent.com/u/60378268?s=200&v=4" width="100px;" alt=""/>
|
|
375
|
-
</a>
|
|
376
|
-
<br />
|
|
377
|
-
<b>Adaptable</b>
|
|
378
|
-
<br/>
|
|
379
|
-
<a href="https://adaptable.io/">adaptable.io</a>
|
|
380
|
-
<br />
|
|
381
|
-
</td>
|
|
382
|
-
<td align="center">
|
|
383
|
-
<a href="https://www.avanawallet.com/">
|
|
384
|
-
<img src="https://avatars.githubusercontent.com/u/105452197?s=200&v=4" width="100px;" alt="Avana Wallet logo"/>
|
|
385
|
-
</a>
|
|
386
|
-
<br />
|
|
387
|
-
<b>Avana Wallet</b>
|
|
388
|
-
<br/>
|
|
389
|
-
<a href="https://www.avanawallet.com/">avanawallet.com</a><br/>
|
|
390
|
-
<span>Solana non-custodial wallet</span>
|
|
391
|
-
<br />
|
|
392
|
-
</td>
|
|
328
|
+
<td>Adaptable</td>
|
|
329
|
+
<td>Avana Wallet</td>
|
|
330
|
+
<td>Jason Lengstorf</td>
|
|
331
|
+
<td>Global Illumination, Inc.</td>
|
|
393
332
|
</tr>
|
|
394
333
|
<tr>
|
|
395
|
-
<td
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
</td>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
</a>
|
|
409
|
-
<br />
|
|
410
|
-
<b>Global Illumination, Inc.</b>
|
|
411
|
-
<br/>
|
|
412
|
-
<a href="https://ill.inc/">ill.inc</a>
|
|
413
|
-
<br />
|
|
414
|
-
</td>
|
|
415
|
-
<td align="center">
|
|
416
|
-
<a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">
|
|
417
|
-
<img src="https://avatars.githubusercontent.com/u/48984031?s=200&v=4" width="100px;" alt="MasterBorn logo"/>
|
|
418
|
-
</a>
|
|
419
|
-
<br />
|
|
420
|
-
<b>MasterBorn</b>
|
|
421
|
-
<br/>
|
|
422
|
-
<a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">masterborn.com</a>
|
|
423
|
-
<br />
|
|
424
|
-
</td>
|
|
334
|
+
<td>MasterBorn</td>
|
|
335
|
+
<td>Ryan Palmer</td>
|
|
336
|
+
<td>Michael Sweeney</td>
|
|
337
|
+
<td>Nextbase</td>
|
|
338
|
+
</tr>
|
|
339
|
+
<tr>
|
|
340
|
+
<td>Remotion</td>
|
|
341
|
+
<td>Connor Sinnott</td>
|
|
342
|
+
<td>Mohammad-Ali A'râbi</td>
|
|
343
|
+
<td>Supatool</td>
|
|
344
|
+
</tr>
|
|
345
|
+
<tr>
|
|
346
|
+
<td>Social Crow</td>
|
|
425
347
|
</tr>
|
|
426
348
|
</table>
|
|
427
349
|
|
|
@@ -439,6 +361,7 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
439
361
|
- [`tRPC`](https://github.com/trpc/trpc): Build end-to-end typesafe APIs without GraphQL.
|
|
440
362
|
- [`@anatine/zod-nestjs`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-nestjs): Helper methods for using Zod in a NestJS project.
|
|
441
363
|
- [`zod-endpoints`](https://github.com/flock-community/zod-endpoints): Contract-first strictly typed endpoints with Zod. OpenAPI compatible.
|
|
364
|
+
- [`zhttp`](https://github.com/evertdespiegeleer/zhttp): An OpenAPI compatible, strictly typed http library with Zod input and response validation.
|
|
442
365
|
- [`domain-functions`](https://github.com/SeasonedSoftware/domain-functions/): Decouple your business logic from your framework using composable functions. With first-class type inference from end to end powered by Zod schemas.
|
|
443
366
|
- [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
|
|
444
367
|
- [`express-zod-api`](https://github.com/RobinTail/express-zod-api): Build Express-based APIs with I/O schema validation and custom middlewares.
|
|
@@ -447,12 +370,12 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
447
370
|
|
|
448
371
|
#### Form integrations
|
|
449
372
|
|
|
450
|
-
- [`conform`](https://conform.guide/api/zod): A progressive enhancement first form validation library for Remix and React Router
|
|
451
373
|
- [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form.
|
|
452
374
|
- [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s.
|
|
453
375
|
- [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod.
|
|
454
376
|
- [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod.
|
|
455
377
|
- [`zodix`](https://github.com/rileytomasek/zodix): Zod utilities for FormData and URLSearchParams in Remix loaders and actions.
|
|
378
|
+
- [`conform`](https://conform.guide/api/zod/parseWithZod): A typesafe form validation library for progressive enhancement of HTML forms. Works with Remix and Next.js.
|
|
456
379
|
- [`remix-params-helper`](https://github.com/kiliman/remix-params-helper): Simplify integration of Zod with standard URLSearchParams and FormData for Remix apps.
|
|
457
380
|
- [`formik-validator-zod`](https://github.com/glazy/formik-validator-zod): Formik-compliant validator library that simplifies using Zod with Formik.
|
|
458
381
|
- [`zod-i18n-map`](https://github.com/aiji42/zod-i18n): Useful for translating Zod error messages.
|
|
@@ -490,6 +413,8 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
490
413
|
- [`zod-prisma-types`](https://github.com/chrishoermann/zod-prisma-types) Create Zod types from your Prisma models.
|
|
491
414
|
- [`quicktype`](https://app.quicktype.io/): Convert JSON objects and JSON schemas into Zod schemas.
|
|
492
415
|
- [`@sanity-typed/zod`](https://github.com/saiichihashimoto/sanity-typed/tree/main/packages/zod): Generate Zod Schemas from [Sanity Schemas](https://www.sanity.io/docs/schema-types).
|
|
416
|
+
- [`java-to-zod`](https://github.com/ivangreene/java-to-zod): Convert POJOs to Zod schemas
|
|
417
|
+
- [`Orval`](https://github.com/anymaniax/orval): Generate Zod schemas from OpenAPI schemas
|
|
493
418
|
|
|
494
419
|
#### Mocking
|
|
495
420
|
|
|
@@ -504,13 +429,18 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
504
429
|
- [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer.
|
|
505
430
|
- [`slonik`](https://github.com/gajus/slonik/tree/gajus/add-zod-validation-backwards-compatible#runtime-validation-and-static-type-inference): Node.js Postgres client with strong Zod integration.
|
|
506
431
|
- [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
|
|
432
|
+
- [`pastel`](https://github.com/vadimdemedes/pastel): Create CLI applications with react, zod, and ink.
|
|
507
433
|
- [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
|
|
508
434
|
- [`znv`](https://github.com/lostfictions/znv): Type-safe environment parsing and validation for Node.js with Zod schemas.
|
|
435
|
+
- [`zod-config`](https://github.com/alexmarqs/zod-config): Load configurations across multiple sources with flexible adapters, ensuring type safety with Zod.
|
|
509
436
|
|
|
510
437
|
#### Utilities for Zod
|
|
511
438
|
|
|
512
439
|
- [`zod_utilz`](https://github.com/JacobWeisenburger/zod_utilz): Framework agnostic utilities for Zod.
|
|
440
|
+
- [`zod-playground`](https://github.com/marilari88/zod-playground): A tool for learning and testing Zod schema validation functionalities. [Link](https://zod-playground.vercel.app/).
|
|
513
441
|
- [`zod-sandbox`](https://github.com/nereumelo/zod-sandbox): Controlled environment for testing zod schemas. [Live demo](https://zod-sandbox.vercel.app/).
|
|
442
|
+
- [`zod-dev`](https://github.com/schalkventer/zod-dev): Conditionally disables Zod runtime parsing in production.
|
|
443
|
+
- [`zod-accelerator`](https://github.com/duplojs/duplojs-zod-accelerator): Accelerates Zod's throughput up to ~100x.
|
|
514
444
|
|
|
515
445
|
## Installation
|
|
516
446
|
|
|
@@ -635,16 +565,26 @@ Zod now provides a more convenient way to coerce primitive values.
|
|
|
635
565
|
const schema = z.coerce.string();
|
|
636
566
|
schema.parse("tuna"); // => "tuna"
|
|
637
567
|
schema.parse(12); // => "12"
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
During the parsing step, the input is passed through the `String()` function, which is a JavaScript built-in for coercing data into strings.
|
|
571
|
+
|
|
572
|
+
```ts
|
|
573
|
+
schema.parse(12); // => "12"
|
|
638
574
|
schema.parse(true); // => "true"
|
|
575
|
+
schema.parse(undefined); // => "undefined"
|
|
576
|
+
schema.parse(null); // => "null"
|
|
639
577
|
```
|
|
640
578
|
|
|
641
|
-
|
|
579
|
+
The returned schema is a normal `ZodString` instance so you can use all string methods.
|
|
642
580
|
|
|
643
581
|
```ts
|
|
644
582
|
z.coerce.string().email().min(5);
|
|
645
583
|
```
|
|
646
584
|
|
|
647
|
-
|
|
585
|
+
**How coercion works**
|
|
586
|
+
|
|
587
|
+
All primitive types support coercion. Zod coerces all inputs using the built-in constructors: `String(input)`, `Number(input)`, `new Date(input)`, etc.
|
|
648
588
|
|
|
649
589
|
```ts
|
|
650
590
|
z.coerce.string(); // String(input)
|
|
@@ -654,22 +594,25 @@ z.coerce.bigint(); // BigInt(input)
|
|
|
654
594
|
z.coerce.date(); // new Date(input)
|
|
655
595
|
```
|
|
656
596
|
|
|
657
|
-
**Boolean coercion
|
|
658
|
-
|
|
659
|
-
Zod's boolean coercion is very simple! It passes the value into the `Boolean(value)` function, that's it. Any truthy value will resolve to `true`, any falsy value will resolve to `false`.
|
|
597
|
+
**Note** — Boolean coercion with `z.coerce.boolean()` may not work how you expect. Any [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) value is coerced to `true`, and any [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value is coerced to `false`.
|
|
660
598
|
|
|
661
599
|
```ts
|
|
662
|
-
z.coerce.boolean()
|
|
663
|
-
z.coerce.boolean().parse("true"); // => true
|
|
664
|
-
z.coerce.boolean().parse("false"); // => true
|
|
665
|
-
z.coerce.boolean().parse(1); // => true
|
|
666
|
-
z.coerce.boolean().parse([]); // => true
|
|
600
|
+
const schema = z.coerce.boolean(); // Boolean(input)
|
|
667
601
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
602
|
+
schema.parse("tuna"); // => true
|
|
603
|
+
schema.parse("true"); // => true
|
|
604
|
+
schema.parse("false"); // => true
|
|
605
|
+
schema.parse(1); // => true
|
|
606
|
+
schema.parse([]); // => true
|
|
607
|
+
|
|
608
|
+
schema.parse(0); // => false
|
|
609
|
+
schema.parse(""); // => false
|
|
610
|
+
schema.parse(undefined); // => false
|
|
611
|
+
schema.parse(null); // => false
|
|
671
612
|
```
|
|
672
613
|
|
|
614
|
+
For more control over coercion logic, consider using [`z.preprocess`](#preprocess) or [`z.pipe()`](#pipe).
|
|
615
|
+
|
|
673
616
|
## Literals
|
|
674
617
|
|
|
675
618
|
Literal schemas represent a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types), like `"hello world"` or `5`.
|
|
@@ -702,6 +645,7 @@ z.string().email();
|
|
|
702
645
|
z.string().url();
|
|
703
646
|
z.string().emoji();
|
|
704
647
|
z.string().uuid();
|
|
648
|
+
z.string().nanoid();
|
|
705
649
|
z.string().cuid();
|
|
706
650
|
z.string().cuid2();
|
|
707
651
|
z.string().ulid();
|
|
@@ -709,13 +653,19 @@ z.string().regex(regex);
|
|
|
709
653
|
z.string().includes(string);
|
|
710
654
|
z.string().startsWith(string);
|
|
711
655
|
z.string().endsWith(string);
|
|
712
|
-
z.string().datetime(); // ISO 8601; default
|
|
713
|
-
z.string().ip(); // defaults to IPv4 and IPv6
|
|
656
|
+
z.string().datetime(); // ISO 8601; by default only `Z` timezone allowed
|
|
657
|
+
z.string().ip(); // defaults to allow both IPv4 and IPv6
|
|
714
658
|
|
|
715
|
-
//
|
|
659
|
+
// transforms
|
|
716
660
|
z.string().trim(); // trim whitespace
|
|
717
661
|
z.string().toLowerCase(); // toLowerCase
|
|
718
662
|
z.string().toUpperCase(); // toUpperCase
|
|
663
|
+
|
|
664
|
+
// added in Zod 3.23
|
|
665
|
+
z.string().date(); // ISO date format (YYYY-MM-DD)
|
|
666
|
+
z.string().time(); // ISO time format (HH:mm:ss[.SSSSSS])
|
|
667
|
+
z.string().duration(); // ISO 8601 duration
|
|
668
|
+
z.string().base64();
|
|
719
669
|
```
|
|
720
670
|
|
|
721
671
|
> Check out [validator.js](https://github.com/validatorjs/validator.js) for a bunch of other useful string validation functions that can be used in conjunction with [Refinements](#refine).
|
|
@@ -743,10 +693,14 @@ z.string().includes("tuna", { message: "Must include tuna" });
|
|
|
743
693
|
z.string().startsWith("https://", { message: "Must provide secure URL" });
|
|
744
694
|
z.string().endsWith(".com", { message: "Only .com domains allowed" });
|
|
745
695
|
z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
|
|
696
|
+
z.string().date({ message: "Invalid date string!" });
|
|
697
|
+
z.string().time({ message: "Invalid time string!" });
|
|
746
698
|
z.string().ip({ message: "Invalid IP address" });
|
|
747
699
|
```
|
|
748
700
|
|
|
749
|
-
###
|
|
701
|
+
### Datetimes
|
|
702
|
+
|
|
703
|
+
As you may have noticed, Zod string includes a few date/time related validations. These validations are regular expression based, so they are not as strict as a full date/time library. However, they are very convenient for validating user input.
|
|
750
704
|
|
|
751
705
|
The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision.
|
|
752
706
|
|
|
@@ -781,6 +735,47 @@ datetime.parse("2020-01-01T00:00:00Z"); // fail
|
|
|
781
735
|
datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
|
|
782
736
|
```
|
|
783
737
|
|
|
738
|
+
### Dates
|
|
739
|
+
|
|
740
|
+
> Added in Zod 3.23
|
|
741
|
+
|
|
742
|
+
The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.
|
|
743
|
+
|
|
744
|
+
```ts
|
|
745
|
+
const date = z.string().date();
|
|
746
|
+
|
|
747
|
+
date.parse("2020-01-01"); // pass
|
|
748
|
+
date.parse("2020-1-1"); // fail
|
|
749
|
+
date.parse("2020-01-32"); // fail
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### Times
|
|
753
|
+
|
|
754
|
+
> Added in Zod 3.23
|
|
755
|
+
|
|
756
|
+
The `z.string().time()` method validates strings in the format `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.
|
|
757
|
+
|
|
758
|
+
```ts
|
|
759
|
+
const time = z.string().time();
|
|
760
|
+
|
|
761
|
+
time.parse("00:00:00"); // pass
|
|
762
|
+
time.parse("09:52:31"); // pass
|
|
763
|
+
time.parse("23:59:59.9999999"); // pass (arbitrary precision)
|
|
764
|
+
|
|
765
|
+
time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
|
|
766
|
+
time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
You can set the `precision` option to constrain the allowable decimal precision.
|
|
770
|
+
|
|
771
|
+
```ts
|
|
772
|
+
const time = z.string().time({ precision: 3 });
|
|
773
|
+
|
|
774
|
+
time.parse("00:00:00.123"); // pass
|
|
775
|
+
time.parse("00:00:00.123456"); // fail
|
|
776
|
+
time.parse("00:00:00"); // fail
|
|
777
|
+
```
|
|
778
|
+
|
|
784
779
|
### IP addresses
|
|
785
780
|
|
|
786
781
|
The `z.string().ip()` method by default validate IPv4 and IPv6.
|
|
@@ -869,7 +864,7 @@ You can customize certain error messages when creating a nan schema.
|
|
|
869
864
|
```ts
|
|
870
865
|
const isNaN = z.nan({
|
|
871
866
|
required_error: "isNaN is required",
|
|
872
|
-
invalid_type_error: "isNaN must be not a number",
|
|
867
|
+
invalid_type_error: "isNaN must be 'not a number'",
|
|
873
868
|
});
|
|
874
869
|
```
|
|
875
870
|
|
|
@@ -953,7 +948,7 @@ const fish = ["Salmon", "Tuna", "Trout"];
|
|
|
953
948
|
const FishEnum = z.enum(fish);
|
|
954
949
|
```
|
|
955
950
|
|
|
956
|
-
|
|
951
|
+
**`.enum`**
|
|
957
952
|
|
|
958
953
|
To get autocompletion with a Zod enum, use the `.enum` property of your schema:
|
|
959
954
|
|
|
@@ -976,6 +971,16 @@ You can also retrieve the list of options as a tuple with the `.options` propert
|
|
|
976
971
|
FishEnum.options; // ["Salmon", "Tuna", "Trout"];
|
|
977
972
|
```
|
|
978
973
|
|
|
974
|
+
**`.exclude/.extract()`**
|
|
975
|
+
|
|
976
|
+
You can create subsets of a Zod enum with the `.exclude` and `.extract` methods.
|
|
977
|
+
|
|
978
|
+
```ts
|
|
979
|
+
const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
|
|
980
|
+
const SalmonAndTrout = FishEnum.extract(["Salmon", "Trout"]);
|
|
981
|
+
const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);
|
|
982
|
+
```
|
|
983
|
+
|
|
979
984
|
## Native enums
|
|
980
985
|
|
|
981
986
|
Zod enums are the recommended approach to defining and validating enums. But if you need to validate against an enum from a third-party library (or you don't want to rewrite your existing enums) you can use `z.nativeEnum()`.
|
|
@@ -1504,28 +1509,49 @@ const myUnion = z.discriminatedUnion("status", [
|
|
|
1504
1509
|
myUnion.parse({ status: "success", data: "yippie ki yay" });
|
|
1505
1510
|
```
|
|
1506
1511
|
|
|
1512
|
+
You can extract a reference to the array of schemas with the `.options` property.
|
|
1513
|
+
|
|
1514
|
+
```ts
|
|
1515
|
+
myUnion.options; // [ZodObject<...>, ZodObject<...>]
|
|
1516
|
+
```
|
|
1517
|
+
|
|
1518
|
+
To merge two or more discriminated unions, use `.options` with destructuring.
|
|
1519
|
+
|
|
1520
|
+
```ts
|
|
1521
|
+
const A = z.discriminatedUnion("status", [
|
|
1522
|
+
/* options */
|
|
1523
|
+
]);
|
|
1524
|
+
const B = z.discriminatedUnion("status", [
|
|
1525
|
+
/* options */
|
|
1526
|
+
]);
|
|
1527
|
+
|
|
1528
|
+
const AB = z.discriminatedUnion("status", [...A.options, ...B.options]);
|
|
1529
|
+
```
|
|
1530
|
+
|
|
1507
1531
|
## Records
|
|
1508
1532
|
|
|
1509
|
-
Record schemas are used to validate types such as `
|
|
1533
|
+
Record schemas are used to validate types such as `Record<string, number>`. This is particularly useful for storing or caching items by ID.
|
|
1510
1534
|
|
|
1511
|
-
If you want to validate the _values_ of an object against some schema but don't care about the keys, use `z.record(valueType)`:
|
|
1535
|
+
<!-- If you want to validate the _values_ of an object against some schema but don't care about the keys, use `z.record(valueType)`:
|
|
1512
1536
|
|
|
1513
1537
|
```ts
|
|
1514
1538
|
const NumberCache = z.record(z.number());
|
|
1515
1539
|
|
|
1516
1540
|
type NumberCache = z.infer<typeof NumberCache>;
|
|
1517
1541
|
// => { [k: string]: number }
|
|
1518
|
-
```
|
|
1519
|
-
|
|
1520
|
-
This is particularly useful for storing or caching items by ID.
|
|
1542
|
+
``` -->
|
|
1521
1543
|
|
|
1522
1544
|
```ts
|
|
1523
|
-
const
|
|
1524
|
-
const userStoreSchema = z.record(userSchema);
|
|
1545
|
+
const User = z.object({ name: z.string() });
|
|
1525
1546
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1547
|
+
const UserStore = z.record(z.string(), User);
|
|
1548
|
+
type UserStore = z.infer<typeof UserStore>;
|
|
1549
|
+
// => Record<string, { name: string }>
|
|
1550
|
+
```
|
|
1528
1551
|
|
|
1552
|
+
The schema and inferred type can be used like so:
|
|
1553
|
+
|
|
1554
|
+
```ts
|
|
1529
1555
|
const userStore: UserStore = {};
|
|
1530
1556
|
|
|
1531
1557
|
userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
|
|
@@ -1537,19 +1563,6 @@ userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
|
|
|
1537
1563
|
}; // TypeError
|
|
1538
1564
|
```
|
|
1539
1565
|
|
|
1540
|
-
### Record key type
|
|
1541
|
-
|
|
1542
|
-
If you want to validate both the keys and the values, use
|
|
1543
|
-
`z.record(keyType, valueType)`:
|
|
1544
|
-
|
|
1545
|
-
```ts
|
|
1546
|
-
const NoEmptyKeysSchema = z.record(z.string().min(1), z.number());
|
|
1547
|
-
NoEmptyKeysSchema.parse({ count: 1 }); // => { 'count': 1 }
|
|
1548
|
-
NoEmptyKeysSchema.parse({ "": 1 }); // fails
|
|
1549
|
-
```
|
|
1550
|
-
|
|
1551
|
-
_(Notice how when passing two arguments, `valueType` is the second argument)_
|
|
1552
|
-
|
|
1553
1566
|
**A note on numerical keys**
|
|
1554
1567
|
|
|
1555
1568
|
While `z.record(keyType, valueType)` is able to accept numerical key types and TypeScript's built-in Record type is `Record<KeyType, ValueType>`, it's hard to represent the TypeScript type `Record<number, any>` in Zod.
|
|
@@ -1729,7 +1742,9 @@ Thanks to [ggoodman](https://github.com/ggoodman) for suggesting this.
|
|
|
1729
1742
|
|
|
1730
1743
|
### Cyclical objects
|
|
1731
1744
|
|
|
1732
|
-
Despite supporting recursive schemas, passing cyclical data into Zod will cause an infinite loop.
|
|
1745
|
+
Despite supporting recursive schemas, passing cyclical data into Zod will cause an infinite loop in some cases.
|
|
1746
|
+
|
|
1747
|
+
> To detect cyclical objects before they cause problems, consider [this approach](https://gist.github.com/colinhacks/d35825e505e635df27cc950776c5500b).
|
|
1733
1748
|
|
|
1734
1749
|
## Promises
|
|
1735
1750
|
|
|
@@ -1775,7 +1790,7 @@ const TestSchema = z.instanceof(Test);
|
|
|
1775
1790
|
|
|
1776
1791
|
const blob: any = "whatever";
|
|
1777
1792
|
TestSchema.parse(new Test()); // passes
|
|
1778
|
-
TestSchema.parse(
|
|
1793
|
+
TestSchema.parse(blob); // throws
|
|
1779
1794
|
```
|
|
1780
1795
|
|
|
1781
1796
|
## Functions
|
|
@@ -2451,7 +2466,7 @@ Note that branded types do not affect the runtime result of `.parse`. It is a st
|
|
|
2451
2466
|
This method returns a `ZodReadonly` schema instance that parses the input using the base schema, then calls `Object.freeze()` on the result. The inferred type is also marked as `readonly`.
|
|
2452
2467
|
|
|
2453
2468
|
```ts
|
|
2454
|
-
const schema = z.object({ name: string }).readonly();
|
|
2469
|
+
const schema = z.object({ name: z.string() }).readonly();
|
|
2455
2470
|
type schema = z.infer<typeof schema>;
|
|
2456
2471
|
// Readonly<{name: string}>
|
|
2457
2472
|
|
|
@@ -2472,7 +2487,7 @@ z.map(z.string(), z.date()).readonly();
|
|
|
2472
2487
|
// ReadonlyMap<string, Date>
|
|
2473
2488
|
|
|
2474
2489
|
z.set(z.string()).readonly();
|
|
2475
|
-
// ReadonlySet<
|
|
2490
|
+
// ReadonlySet<string>
|
|
2476
2491
|
```
|
|
2477
2492
|
|
|
2478
2493
|
### `.pipe`
|
|
@@ -2576,36 +2591,63 @@ type inferred = z.infer<typeof stringToNumber>; // number
|
|
|
2576
2591
|
|
|
2577
2592
|
### Writing generic functions
|
|
2578
2593
|
|
|
2579
|
-
|
|
2594
|
+
With TypeScript generics, you can write reusable functions that accept Zod schemas as parameters. This enables you to create custom validation logic, schema transformations, and more, while maintaining type safety and inference.
|
|
2595
|
+
|
|
2596
|
+
When attempting to write a function that accepts a Zod schema as an input, it's tempting to try something like this:
|
|
2580
2597
|
|
|
2581
2598
|
```ts
|
|
2582
|
-
function
|
|
2583
|
-
return schema
|
|
2599
|
+
function inferSchema<T>(schema: z.ZodType<T>) {
|
|
2600
|
+
return schema;
|
|
2584
2601
|
}
|
|
2585
2602
|
```
|
|
2586
2603
|
|
|
2587
|
-
This approach
|
|
2604
|
+
This approach is incorrect, and limits TypeScript's ability to properly infer the argument. No matter what you pass in, the type of `schema` will be an instance of `ZodType`.
|
|
2588
2605
|
|
|
2589
2606
|
```ts
|
|
2590
|
-
|
|
2591
|
-
|
|
2607
|
+
inferSchema(z.string());
|
|
2608
|
+
// => ZodType<string>
|
|
2592
2609
|
```
|
|
2593
2610
|
|
|
2594
|
-
|
|
2611
|
+
This approach loses type information, namely _which subclass_ the input actually is (in this case, `ZodString`). That means you can't call any string-specific methods like `.min()` on the result of `inferSchema`.
|
|
2612
|
+
|
|
2613
|
+
A better approach is to infer _the schema as a whole_ instead of merely its inferred type. You can do this with a utility type called `z.ZodTypeAny`.
|
|
2595
2614
|
|
|
2596
2615
|
```ts
|
|
2597
|
-
function
|
|
2598
|
-
return schema
|
|
2616
|
+
function inferSchema<T extends z.ZodTypeAny>(schema: T) {
|
|
2617
|
+
return schema;
|
|
2599
2618
|
}
|
|
2619
|
+
|
|
2620
|
+
inferSchema(z.string());
|
|
2621
|
+
// => ZodString
|
|
2600
2622
|
```
|
|
2601
2623
|
|
|
2602
2624
|
> `ZodTypeAny` is just a shorthand for `ZodType<any, any, any>`, a type that is broad enough to match any Zod schema.
|
|
2603
2625
|
|
|
2604
|
-
|
|
2626
|
+
The Result is now fully and properly typed, and the type system can infer the specific subclass of the schema.
|
|
2627
|
+
|
|
2628
|
+
#### Inferring the inferred type
|
|
2629
|
+
|
|
2630
|
+
If you follow the best practice of using `z.ZodTypeAny` as the generic parameter for your schema, you may encounter issues with the parsed data being typed as `any` instead of the inferred type of the schema.
|
|
2605
2631
|
|
|
2606
2632
|
```ts
|
|
2607
|
-
|
|
2608
|
-
|
|
2633
|
+
function parseData<T extends z.ZodTypeAny>(data: unknown, schema: T) {
|
|
2634
|
+
return schema.parse(data);
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
parseData("sup", z.string());
|
|
2638
|
+
// => any
|
|
2639
|
+
```
|
|
2640
|
+
|
|
2641
|
+
Due to how TypeScript inference works, it is treating `schema` like a `ZodTypeAny` instead of the inferred type. You can fix this with a type cast using `z.infer`.
|
|
2642
|
+
|
|
2643
|
+
```ts
|
|
2644
|
+
function parseData<T extends z.ZodTypeAny>(data: unknown, schema: T) {
|
|
2645
|
+
return schema.parse(data) as z.infer<T>;
|
|
2646
|
+
// ^^^^^^^^^^^^^^ <- add this
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
parseData("sup", z.string());
|
|
2650
|
+
// => string
|
|
2609
2651
|
```
|
|
2610
2652
|
|
|
2611
2653
|
#### Constraining allowable inputs
|