zod 3.22.4 → 3.23.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,7 +69,9 @@
69
69
  - [Coercion for primitives](#coercion-for-primitives)
70
70
  - [Literals](#literals)
71
71
  - [Strings](#strings)
72
- - [ISO datetimes](#iso-datetimes)
72
+ - [Datetimes](#datetimes)
73
+ - [Dates](#dates)
74
+ - [Times](#times)
73
75
  - [IP addresses](#ip-addresses)
74
76
  - [Numbers](#numbers)
75
77
  - [BigInts](#bigints)
@@ -185,88 +187,135 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
185
187
  <table>
186
188
  <tr>
187
189
  <td align="center">
188
- <a href="https://speakeasyapi.dev/">
190
+ <a href="https://speakeasyapi.dev/" target="_blank">
189
191
  <img src="https://avatars.githubusercontent.com/u/91446104?s=200&v=4" width="200px;" alt="Speakeasy API" />
190
192
  </a>
191
193
  <br />
192
194
  <b>Speakeasy</b>
193
195
  <br />
194
- <a href="https://speakeasyapi.dev/">speakeasyapi.dev</a>
196
+ <a href="https://speakeasyapi.dev/" target="_blank">speakeasyapi.dev</a>
195
197
  <br />
196
- <p width="200px">SDKs, Terraform, Docs.<br/>Your API made enterprise-ready.</p>
198
+ <p width="200px">SDKs, Terraform, Docs.<br/>Your API made enterprise-ready</p>
197
199
  </td>
198
200
  <td align="center">
199
- <a href="https://glow.app/">
200
- <img src="https://i.imgur.com/R0R43S2.jpg" width="200px;" alt="Glow Wallet" />
201
- </a>
202
- <br />
203
- <b>Glow Wallet</b>
204
- <br />
205
- <a href="https://glow.app/">glow.app</a>
206
- <br />
207
- <p width="200px">Your new favorite
208
- <br/>
209
- Solana wallet.</p>
210
- </td>
211
- </tr>
212
- <tr>
213
- <td align="center">
214
- <a href="https://deletype.com/">
201
+ <a href="https://deletype.com/" target="_blank">
215
202
  <img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="Deletype logo" />
216
203
  </a>
217
204
  <br />
218
205
  <b>Deletype</b>
219
206
  <br />
220
- <a href="https://deletype.com">deletype.com</a>
207
+ <a href="https://deletype.com" target="_blank">deletype.com</a>
221
208
  </td>
209
+ </tr>
210
+ <tr>
222
211
  <td align="center">
223
- <a href="https://trigger.dev/">
212
+ <a href="https://trigger.dev/" target="_blank">
224
213
  <img src="https://avatars.githubusercontent.com/u/95297378?s=200&v=4" width="200px;" alt="Trigger.dev logo" />
225
214
  </a>
226
215
  <br />
227
216
  <b>Trigger.dev</b>
228
217
  <br />
229
- <a href="https://trigger.dev">trigger.dev</a>
218
+ <a href="https://trigger.dev" target="_blank">trigger.dev</a>
230
219
  <br/>
231
- <p>Effortless automation for developers.</p>
220
+ <p>Effortless automation for developers</p>
232
221
  </td>
233
- </tr>
234
- <tr>
235
222
  <td align="center">
236
- <a href="https://transloadit.com/?utm_source=zod&utm_medium=referral&utm_campaign=sponsorship&utm_content=github">
223
+ <a href="https://transloadit.com/?utm_source=zod&utm_medium=referral&utm_campaign=sponsorship&utm_content=github" target="_blank">
237
224
  <img src="https://avatars.githubusercontent.com/u/125754?s=200&v=4" width="200px;" alt="Transloadit logo" />
238
225
  </a>
239
226
  <br />
240
227
  <b>Transloadit</b>
241
228
  <br />
242
- <a href="https://transloadit.com/?utm_source=zod&utm_medium=referral&utm_campaign=sponsorship&utm_content=github">transloadit.com</a>
229
+ <a href="https://transloadit.com/?utm_source=zod&utm_medium=referral&utm_campaign=sponsorship&utm_content=github" target="_blank">transloadit.com</a>
243
230
  <br/>
244
- <p>Simple file processing for developers.</p>
231
+ <p>Simple file processing for developers</p>
245
232
  </td>
233
+ </tr>
234
+ <tr>
246
235
  <td align="center">
247
- <a href="https://infisical.com">
236
+ <a href="https://infisical.com" target="_blank">
248
237
  <img src="https://avatars.githubusercontent.com/u/107880645?s=200&v=4" width="200px;" alt="Infisical logo" />
249
238
  </a>
250
239
  <br />
251
240
  <b>Infisical</b>
252
241
  <br />
253
- <a href="https://infisical.com">infisical.com</a>
242
+ <a href="https://infisical.com" target="_blank">infisical.com</a>
254
243
  <br/>
255
- <p>Open-source platform for secret<br/>management: sync secrets across your<br/>team/infrastructure and prevent secret leaks.</p>
244
+ <p>Open-source platform for secret<br/>management: sync secrets across your<br/>team/infrastructure and prevent secret leaks</p>
256
245
  </td>
257
- </tr>
258
- <tr>
259
246
  <td align="center">
260
- <a href="https://whop.com/">
247
+ <a href="https://whop.com/" target="_blank">
261
248
  <img src="https://avatars.githubusercontent.com/u/91036480?s=200&v=4" width="200px;" alt="Whop logo" />
262
249
  </a>
263
250
  <br />
264
251
  <b>Whop</b>
265
252
  <br />
266
- <a href="https://whop.com/">whop.com</a>
253
+ <a href="https://whop.com/" target="_blank">whop.com</a>
254
+ <br />
255
+ <p width="200px">A marketplace for really cool internet products</p>
256
+ </td>
257
+ </tr>
258
+ <tr>
259
+ <td align="center">
260
+ <a href="https://cryptojobslist.com/" target="_blank">
261
+ <img src="https://avatars.githubusercontent.com/u/36402888?s=200&v=4" width="200px;" alt="CryptoJobsList logo" />
262
+ </a>
263
+ <br />
264
+ <b>CryptoJobsList</b>
265
+ <br />
266
+ <a href="https://cryptojobslist.com/" target="_blank">cryptojobslist.com</a>
267
+ <br />
268
+ <p width="200px">The biggest list of crypto, blockchain and Web3 jobs</p>
269
+ </td>
270
+ <td align="center">
271
+ <a href="https://plain.com/" target="_blank">
272
+ <img src="https://avatars.githubusercontent.com/u/70170949?s=200&v=4" width="200px;" alt="Plain logo" />
273
+ </a>
274
+ <br />
275
+ <b>Plain.</b>
276
+ <br />
277
+ <a href="https://plain.com/" target="_blank">plain.com</a>
278
+ <br />
279
+ <p width="200px">How developers support their users</p>
280
+ </td>
281
+ </tr>
282
+ <tr>
283
+ <td align="center">
284
+ <a href="https://inngest.com/" target="_blank">
285
+ <img src="https://avatars.githubusercontent.com/u/78935958?s=200&v=4" width="200px;" alt="Inngest logo" />
286
+ </a>
287
+ <br />
288
+ <b>Inngest</b>
289
+ <br />
290
+ <a href="https://inngest.com/" target="_blank">inngest.com</a>
291
+ <br />
292
+ <p width="200px">Serverless queues + durable workflows for TypeScript</p>
293
+ </td>
294
+ <td align="center">
295
+ <a href="https://storyblok.com/" target="_blank">
296
+ <img src="https://avatars.githubusercontent.com/u/13880908?s=200&v=4" width="200px;" alt="Storyblok CMS" />
297
+ </a>
298
+ <br />
299
+ <b>Storyblok</b>
300
+ <br />
301
+ <a href="https://storyblok.com/" target="_blank">storyblok.com</a>
302
+ <br />
303
+ <p width="200px">The only headless CMS with a visual editor</p>
304
+ </td>
305
+ </tr>
306
+ <tr>
307
+ <td align="center">
308
+ <a href="https://mux.link/zod" target="_blank">
309
+ <img src="https://avatars.githubusercontent.com/u/16199997?s=200&v=4" width="200px;" alt="Mux logo" />
310
+ </a>
311
+ <br />
312
+ <b>Mux</b>
267
313
  <br />
268
- <p width="200px">A marketplace for really cool internet products.</p>
314
+ <a href="https://mux.link/zod" target="_blank">mux.com</a>
315
+ <br />
316
+ <p width="200px">The internet's video infrastructure</p>
269
317
  </td>
318
+ </tr>
270
319
  </table>
271
320
 
272
321
  #### Silver
@@ -274,51 +323,51 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
274
323
  <table>
275
324
  <tr>
276
325
  <td align="center" colspan="2">
277
- <a href="https://www.numeric.io">
326
+ <a href="https://www.numeric.io" target="_blank">
278
327
  <img src="https://i.imgur.com/kTiLtZt.png" width="250px;" alt="Numeric logo" />
279
328
  </a>
280
329
  <br />
281
330
  <b>Numeric</b>
282
331
  <br />
283
- <a href="https://www.numeric.io">numeric.io</a>
332
+ <a href="https://www.numeric.io" target="_blank">numeric.io</a>
284
333
  </td>
285
334
  <td align="center">
286
- <a href="https://marcatopartners.com/">
335
+ <a href="https://marcatopartners.com/" target="_blank">
287
336
  <img src="https://avatars.githubusercontent.com/u/84106192?s=200&v=4" width="150px;" alt="Marcato Partners" />
288
337
  </a>
289
338
  <br />
290
339
  <b>Marcato Partners</b>
291
340
  <br />
292
- <a href="https://marcatopartners.com/">marcatopartners.com</a>
341
+ <a href="https://marcatopartners.com/" target="_blank">marcatopartners.com</a>
293
342
  </td>
294
343
  </tr>
295
344
  <tr>
296
345
  <td align="center">
297
- <a href="https://interval.com">
346
+ <a href="https://interval.com" target="_blank">
298
347
  <img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4" width="150px;" alt="" />
299
348
  </a>
300
349
  <br />
301
350
  <b>Interval</b>
302
351
  <br />
303
- <a href="https://interval.com">interval.com</a>
352
+ <a href="https://interval.com" target="_blank">interval.com</a>
304
353
  </td>
305
354
  <td align="center">
306
- <a href="https://seasoned.cc">
355
+ <a href="https://seasoned.cc" target="_blank">
307
356
  <img src="https://avatars.githubusercontent.com/u/33913103?s=200&v=4" width="150px;" alt="" />
308
357
  </a>
309
358
  <br />
310
359
  <b>Seasoned Software</b>
311
360
  <br />
312
- <a href="https://seasoned.cc">seasoned.cc</a>
361
+ <a href="https://seasoned.cc" target="_blank">seasoned.cc</a>
313
362
  </td>
314
363
  <td align="center">
315
- <a href="https://www.bamboocreative.nz/">
364
+ <a href="https://www.bamboocreative.nz/" target="_blank">
316
365
  <img src="https://avatars.githubusercontent.com/u/41406870?v=4" width="150px;" alt="Bamboo Creative logo" />
317
366
  </a>
318
367
  <br />
319
368
  <b>Bamboo Creative</b>
320
369
  <br />
321
- <a href="https://www.bamboocreative.nz">bamboocreative.nz</a>
370
+ <a href="https://www.bamboocreative.nz" target="_blank">bamboocreative.nz</a>
322
371
  </td>
323
372
  </tr>
324
373
  </table>
@@ -328,98 +377,174 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
328
377
  <table>
329
378
  <tr>
330
379
  <td align="center">
331
- <a href="https://twitter.com/flybayer">
380
+ <a href="https://twitter.com/flybayer" target="_blank">
332
381
  <img src="https://avatars2.githubusercontent.com/u/8813276?s=460&u=4ff8beb9a67b173015c4b426a92d89cab960af1b&v=4" width="100px;" alt=""/>
333
382
  </a>
334
383
  <br />
335
384
  <b>Brandon Bayer</b>
336
385
  <br/>
337
- <a href="https://twitter.com/flybayer">@flybayer</a>,
386
+ <a href="https://twitter.com/flybayer" target="_blank">@flybayer</a>,
338
387
  <span>creator of <a href="https://blitzjs.com">Blitz.js</a></span>
339
388
  <br />
340
389
  </td>
341
390
  <td align="center">
342
- <a href="https://github.com/brabeji">
391
+ <a href="https://github.com/brabeji" target="_blank">
343
392
  <img src="https://avatars.githubusercontent.com/u/2237954?v=4" width="100px;" alt=""/>
344
393
  </a>
345
394
  <br />
346
395
  <b>Jiří Brabec</b>
347
396
  <br/>
348
- <a href="https://github.com/brabeji">@brabeji</a>
397
+ <a href="https://github.com/brabeji" target="_blank">@brabeji</a>
349
398
  <br />
350
399
  </td>
351
400
  <td align="center">
352
- <a href="https://twitter.com/alexdotjs">
401
+ <a href="https://twitter.com/alexdotjs" target="_blank">
353
402
  <img src="https://avatars.githubusercontent.com/u/459267?v=4" width="100px;" alt="" />
354
403
  </a>
355
404
  <br />
356
405
  <b>Alex Johansson</b>
357
406
  <br />
358
- <a href="https://twitter.com/alexdotjs">@alexdotjs</a>
407
+ <a href="https://twitter.com/alexdotjs" target="_blank">@alexdotjs</a>
359
408
  </td>
360
409
  </tr>
361
410
  <tr>
362
411
  <td align="center">
363
- <a href="https://fungible.systems/">
412
+ <a href="https://fungible.systems/" target="_blank">
364
413
  <img src="https://avatars.githubusercontent.com/u/80220121?s=200&v=4" width="100px;" alt="Fungible Systems logo"/>
365
414
  </a>
366
415
  <br />
367
416
  <b>Fungible Systems</b>
368
417
  <br/>
369
- <a href="https://fungible.systems/">fungible.systems</a>
418
+ <a href="https://fungible.systems/" target="_blank">fungible.systems</a>
370
419
  <br />
371
420
  </td>
372
421
  <td align="center">
373
- <a href="https://adaptable.io/">
422
+ <a href="https://adaptable.io/" target="_blank">
374
423
  <img src="https://avatars.githubusercontent.com/u/60378268?s=200&v=4" width="100px;" alt=""/>
375
424
  </a>
376
425
  <br />
377
426
  <b>Adaptable</b>
378
427
  <br/>
379
- <a href="https://adaptable.io/">adaptable.io</a>
428
+ <a href="https://adaptable.io/" target="_blank">adaptable.io</a>
380
429
  <br />
381
430
  </td>
382
431
  <td align="center">
383
- <a href="https://www.avanawallet.com/">
432
+ <a href="https://www.avanawallet.com/" target="_blank">
384
433
  <img src="https://avatars.githubusercontent.com/u/105452197?s=200&v=4" width="100px;" alt="Avana Wallet logo"/>
385
434
  </a>
386
435
  <br />
387
436
  <b>Avana Wallet</b>
388
437
  <br/>
389
- <a href="https://www.avanawallet.com/">avanawallet.com</a><br/>
438
+ <a href="https://www.avanawallet.com/" target="_blank">avanawallet.com</a><br/>
390
439
  <span>Solana non-custodial wallet</span>
391
440
  <br />
392
441
  </td>
393
442
  </tr>
394
443
  <tr>
395
444
  <td align="center">
396
- <a href="https://learnwithjason.dev">
445
+ <a href="https://learnwithjason.dev" target="_blank">
397
446
  <img src="https://avatars.githubusercontent.com/u/66575486?s=200&v=4" width="100px;" alt="Learn with Jason logo"/>
398
447
  </a>
399
448
  <br />
400
449
  <b>Jason Lengstorf</b>
401
450
  <br/>
402
- <a href="https://learnwithjason.dev/">learnwithjason.dev</a>
451
+ <a href="https://learnwithjason.dev/" target="_blank">learnwithjason.dev</a>
403
452
  <br />
404
453
  </td>
405
454
  <td align="center">
406
- <a href="https://ill.inc/">
455
+ <a href="https://ill.inc/" target="_blank">
407
456
  <img src="https://avatars.githubusercontent.com/u/89107581?s=200&v=4" width="100px;" alt="Global Illumination"/>
408
457
  </a>
409
458
  <br />
410
459
  <b>Global Illumination, Inc.</b>
411
460
  <br/>
412
- <a href="https://ill.inc/">ill.inc</a>
461
+ <a href="https://ill.inc/" target="_blank">ill.inc</a>
413
462
  <br />
414
463
  </td>
415
- <td align="center">
416
- <a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">
464
+ <td align="center">
465
+ <a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring" target="_blank">
417
466
  <img src="https://avatars.githubusercontent.com/u/48984031?s=200&v=4" width="100px;" alt="MasterBorn logo"/>
418
467
  </a>
419
468
  <br />
420
469
  <b>MasterBorn</b>
421
470
  <br/>
422
- <a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">masterborn.com</a>
471
+ <a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring" target="_blank">masterborn.com</a>
472
+ <br />
473
+ </td>
474
+ </tr>
475
+ <tr>
476
+ <td align="center">
477
+ <a href="https://github.com/kronodeus" target="_blank">
478
+ <img src="https://avatars.githubusercontent.com/u/18314366?v=4" width="100px;" alt="Ryan Palmer"/>
479
+ </a>
480
+ <br />
481
+ <b>Ryan Palmer</b>
482
+ <br/>
483
+ <a href="https://github.com/kronodeus" target="_blank">@kronodeus</a>
484
+ <br />
485
+ </td>
486
+ <td align="center">
487
+ <a href="https://github.com/overthemike" target="_blank">
488
+ <img src="https://avatars.githubusercontent.com/u/223509?v=4" width="100px;" alt="Michael Sweeney"/>
489
+ </a>
490
+ <br />
491
+ <b>Michael Sweeney</b>
492
+ <br/>
493
+ <a href="https://github.com/overthemike" target="_blank">@overthemike</a>
494
+ <br />
495
+ </td>
496
+ <td align="center">
497
+ <a href="https://usenextbase.com/" target="_blank">
498
+ <img src="https://pbs.twimg.com/profile_images/1692236063409070080/28yXFtop_400x400.jpg" width="100px;" alt="Nextbase logo"/>
499
+ </a>
500
+ <br />
501
+ <b>Nextbase</b>
502
+ <br/>
503
+ <a href="https://usenextbase.com/" target="_blank">usenextbase.com</a>
504
+ <br />
505
+ </td>
506
+ </tr>
507
+ <tr>
508
+ <td align="center">
509
+ <a href="https://remotion.dev" target="_blank">
510
+ <img src="https://avatars.githubusercontent.com/u/85344006" width="100px;" alt="Remotion logo"/>
511
+ </a>
512
+ <br />
513
+ <b>Remotion</b>
514
+ <br/>
515
+ <a href="https://remotion.dev" target="_blank">remotion.dev</a>
516
+ <br />
517
+ </td>
518
+ <td align="center">
519
+ <a href="https://github.com/ConnorSinnott" target="_blank">
520
+ <img src="https://avatars.githubusercontent.com/u/12754711?v=4" width="100px;" alt="Connor Sinnott profile"/>
521
+ </a>
522
+ <br />
523
+ <b>Connor Sinnott</b>
524
+ <br/>
525
+ <a href="https://github.com/ConnorSinnott" target="_blank">@ConnorSinnott</a>
526
+ <br />
527
+ </td>
528
+ <td align="center">
529
+ <a href="https://aerabi.com/" target="_blank">
530
+ <img src="https://avatars.githubusercontent.com/u/44623032?v=4" width="100px;" alt="aerabi"/>
531
+ </a>
532
+ <br />
533
+ <b>Mohammad-Ali A'râbi</b>
534
+ <br/>
535
+ <a href="https://aerabi.com/" target="_blank">aerabi.com</a>
536
+ <br />
537
+ </td>
538
+ </tr>
539
+ <tr>
540
+ <td align="center">
541
+ <a href="https://supatool.io/" target="_blank">
542
+ <img src="https://github.com/colinhacks/zod/assets/3084745/d0ec96c9-bf79-494f-9caa-9233da251f55" width="100px;" alt="Supatool logo"/>
543
+ </a>
544
+ <br />
545
+ <b>Supatool</b>
546
+ <br/>
547
+ <a href="https://supatool.io/" target="_blank">supatool.io</a>
423
548
  <br />
424
549
  </td>
425
550
  </tr>
@@ -439,6 +564,7 @@ There are a growing number of tools that are built atop or support Zod natively!
439
564
  - [`tRPC`](https://github.com/trpc/trpc): Build end-to-end typesafe APIs without GraphQL.
440
565
  - [`@anatine/zod-nestjs`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-nestjs): Helper methods for using Zod in a NestJS project.
441
566
  - [`zod-endpoints`](https://github.com/flock-community/zod-endpoints): Contract-first strictly typed endpoints with Zod. OpenAPI compatible.
567
+ - [`zhttp`](https://github.com/evertdespiegeleer/zhttp): An OpenAPI compatible, strictly typed http library with Zod input and response validation.
442
568
  - [`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
569
  - [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
444
570
  - [`express-zod-api`](https://github.com/RobinTail/express-zod-api): Build Express-based APIs with I/O schema validation and custom middlewares.
@@ -447,12 +573,12 @@ There are a growing number of tools that are built atop or support Zod natively!
447
573
 
448
574
  #### Form integrations
449
575
 
450
- - [`conform`](https://conform.guide/api/zod): A progressive enhancement first form validation library for Remix and React Router
451
576
  - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form.
452
577
  - [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s.
453
578
  - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod.
454
579
  - [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod.
455
580
  - [`zodix`](https://github.com/rileytomasek/zodix): Zod utilities for FormData and URLSearchParams in Remix loaders and actions.
581
+ - [`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
582
  - [`remix-params-helper`](https://github.com/kiliman/remix-params-helper): Simplify integration of Zod with standard URLSearchParams and FormData for Remix apps.
457
583
  - [`formik-validator-zod`](https://github.com/glazy/formik-validator-zod): Formik-compliant validator library that simplifies using Zod with Formik.
458
584
  - [`zod-i18n-map`](https://github.com/aiji42/zod-i18n): Useful for translating Zod error messages.
@@ -490,6 +616,8 @@ There are a growing number of tools that are built atop or support Zod natively!
490
616
  - [`zod-prisma-types`](https://github.com/chrishoermann/zod-prisma-types) Create Zod types from your Prisma models.
491
617
  - [`quicktype`](https://app.quicktype.io/): Convert JSON objects and JSON schemas into Zod schemas.
492
618
  - [`@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).
619
+ - [`java-to-zod`](https://github.com/ivangreene/java-to-zod): Convert POJOs to Zod schemas
620
+ - [`Orval`](https://github.com/anymaniax/orval): Generate Zod schemas from OpenAPI schemas
493
621
 
494
622
  #### Mocking
495
623
 
@@ -504,13 +632,17 @@ There are a growing number of tools that are built atop or support Zod natively!
504
632
  - [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer.
505
633
  - [`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
634
  - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
635
+ - [`pastel`](https://github.com/vadimdemedes/pastel): Create CLI applications with react, zod, and ink.
507
636
  - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
508
637
  - [`znv`](https://github.com/lostfictions/znv): Type-safe environment parsing and validation for Node.js with Zod schemas.
638
+ - [`zod-config`](https://github.com/alexmarqs/zod-config): Load configurations across multiple sources with flexible adapters, ensuring type safety with Zod.
509
639
 
510
640
  #### Utilities for Zod
511
641
 
512
642
  - [`zod_utilz`](https://github.com/JacobWeisenburger/zod_utilz): Framework agnostic utilities for Zod.
513
643
  - [`zod-sandbox`](https://github.com/nereumelo/zod-sandbox): Controlled environment for testing zod schemas. [Live demo](https://zod-sandbox.vercel.app/).
644
+ - [`zod-dev`](https://github.com/schalkventer/zod-dev): Conditionally disables Zod runtime parsing in production.
645
+ - [`zod-accelerator`](https://github.com/duplojs/duplojs-zod-accelerator): Accelerates Zod's throughput up to ~100x.
514
646
 
515
647
  ## Installation
516
648
 
@@ -635,16 +767,19 @@ Zod now provides a more convenient way to coerce primitive values.
635
767
  const schema = z.coerce.string();
636
768
  schema.parse("tuna"); // => "tuna"
637
769
  schema.parse(12); // => "12"
638
- schema.parse(true); // => "true"
639
770
  ```
640
771
 
641
- During the parsing step, the input is passed through the `String()` function, which is a JavaScript built-in for coercing data into strings. Note that the returned schema is a `ZodString` instance so you can use all string methods.
772
+ During the parsing step, the input is passed through the `String()` function, which is a JavaScript built-in for coercing data into strings.
773
+
774
+ The returned schema is a normal `ZodString` instance so you can use all string methods.
642
775
 
643
776
  ```ts
644
777
  z.coerce.string().email().min(5);
645
778
  ```
646
779
 
647
- All primitive types support coercion.
780
+ **How coercion works**
781
+
782
+ All primitive types support coercion. Zod coerces all inputs using the built-in constructors: `String(input)`, `Number(input)`, `new Date(input)`, etc.
648
783
 
649
784
  ```ts
650
785
  z.coerce.string(); // String(input)
@@ -654,9 +789,19 @@ z.coerce.bigint(); // BigInt(input)
654
789
  z.coerce.date(); // new Date(input)
655
790
  ```
656
791
 
792
+ Note that some behavior may not be what you expect.
793
+
794
+ ```ts
795
+ schema.parse(true); // => "true"
796
+ schema.parse(undefined); // => "undefined"
797
+ schema.parse(null); // => "null"
798
+ ```
799
+
800
+ For more control over coercion logic, consider using [`z.preprocess`](#preprocess) or [`z.pipe()`](#pipe).
801
+
657
802
  **Boolean coercion**
658
803
 
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`.
804
+ Zod's approach to 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`.
660
805
 
661
806
  ```ts
662
807
  z.coerce.boolean().parse("tuna"); // => true
@@ -666,6 +811,7 @@ z.coerce.boolean().parse(1); // => true
666
811
  z.coerce.boolean().parse([]); // => true
667
812
 
668
813
  z.coerce.boolean().parse(0); // => false
814
+ z.coerce.boolean().parse(""); // => false
669
815
  z.coerce.boolean().parse(undefined); // => false
670
816
  z.coerce.boolean().parse(null); // => false
671
817
  ```
@@ -702,6 +848,7 @@ z.string().email();
702
848
  z.string().url();
703
849
  z.string().emoji();
704
850
  z.string().uuid();
851
+ z.string().nanoid();
705
852
  z.string().cuid();
706
853
  z.string().cuid2();
707
854
  z.string().ulid();
@@ -709,10 +856,14 @@ z.string().regex(regex);
709
856
  z.string().includes(string);
710
857
  z.string().startsWith(string);
711
858
  z.string().endsWith(string);
712
- z.string().datetime(); // ISO 8601; default is without UTC offset, see below for options
713
- z.string().ip(); // defaults to IPv4 and IPv6, see below for options
714
-
715
- // transformations
859
+ z.string().datetime(); // ISO 8601; by default only `Z` timezone allowed
860
+ z.string().date(); // ISO date format (YYYY-MM-DD)
861
+ z.string().time(); // ISO time format (HH:mm:ss[.SSSSSS])
862
+ z.string().duration(); // ISO 8601 duration
863
+ z.string().ip(); // defaults to allow both IPv4 and IPv6
864
+ z.string().base64();
865
+
866
+ // transforms
716
867
  z.string().trim(); // trim whitespace
717
868
  z.string().toLowerCase(); // toLowerCase
718
869
  z.string().toUpperCase(); // toUpperCase
@@ -743,10 +894,18 @@ z.string().includes("tuna", { message: "Must include tuna" });
743
894
  z.string().startsWith("https://", { message: "Must provide secure URL" });
744
895
  z.string().endsWith(".com", { message: "Only .com domains allowed" });
745
896
  z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
897
+ z.string().date({ message: "Invalid date string!" });
898
+ z.string().time({ message: "Invalid time string!" });
746
899
  z.string().ip({ message: "Invalid IP address" });
747
900
  ```
748
901
 
749
- ### ISO datetimes
902
+ ### Datetimes
903
+
904
+ 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.
905
+
906
+ The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.
907
+
908
+ The `z.string().time()` method validates strings in the format `HH:mm:ss[.SSSSSS][Z|(+|-)hh[:]mm]` (the time portion of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)). It defaults to `HH:mm:ss[.SSSSSS]` validation: no timezone offsets or `Z`, with arbitrary sub-second decimal.
750
909
 
751
910
  The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision.
752
911
 
@@ -779,6 +938,49 @@ const datetime = z.string().datetime({ precision: 3 });
779
938
  datetime.parse("2020-01-01T00:00:00.123Z"); // pass
780
939
  datetime.parse("2020-01-01T00:00:00Z"); // fail
781
940
  datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
941
+
942
+ const time = z.string().time({ precision: 3 });
943
+
944
+ time.parse("00:00:00.123"); // pass
945
+ time.parse("00:00:00"); // fail
946
+ time.parse("00:00:00.123456"); // fail
947
+ ```
948
+
949
+ ### Dates
950
+
951
+ The `z.string().date()` method validates strings in the format `YYYY-MM-DD`.
952
+
953
+ ```ts
954
+ const date = z.string().date();
955
+
956
+ date.parse("2020-01-01"); // pass
957
+ date.parse("2020-1-1"); // fail
958
+ date.parse("2020-01-32"); // fail
959
+ ```
960
+
961
+ ### Times
962
+
963
+ 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.
964
+
965
+ ```ts
966
+ const time = z.string().time();
967
+
968
+ time.parse("00:00:00"); // pass
969
+ time.parse("09:52:31"); // pass
970
+ time.parse("23:59:59.9999999"); // pass (arbitrary precision)
971
+
972
+ time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
973
+ time.parse("00:00:00.123+02:00"); // fail (no offsets allowed)
974
+ ```
975
+
976
+ You can set the `precision` option to constrain the allowable decimal precision.
977
+
978
+ ```ts
979
+ const time = z.string().time({ precision: 3 });
980
+
981
+ time.parse("00:00:00.123"); // pass
982
+ time.parse("00:00:00.123456"); // fail
983
+ time.parse("00:00:00"); // fail
782
984
  ```
783
985
 
784
986
  ### IP addresses
@@ -869,7 +1071,7 @@ You can customize certain error messages when creating a nan schema.
869
1071
  ```ts
870
1072
  const isNaN = z.nan({
871
1073
  required_error: "isNaN is required",
872
- invalid_type_error: "isNaN must be not a number",
1074
+ invalid_type_error: "isNaN must be 'not a number'",
873
1075
  });
874
1076
  ```
875
1077
 
@@ -953,7 +1155,7 @@ const fish = ["Salmon", "Tuna", "Trout"];
953
1155
  const FishEnum = z.enum(fish);
954
1156
  ```
955
1157
 
956
- **Autocompletion**
1158
+ **`.enum`**
957
1159
 
958
1160
  To get autocompletion with a Zod enum, use the `.enum` property of your schema:
959
1161
 
@@ -976,6 +1178,16 @@ You can also retrieve the list of options as a tuple with the `.options` propert
976
1178
  FishEnum.options; // ["Salmon", "Tuna", "Trout"];
977
1179
  ```
978
1180
 
1181
+ **`.exclude/.extract()`**
1182
+
1183
+ You can create subsets of a Zod enum with the `.exclude` and `.extract` methods.
1184
+
1185
+ ```ts
1186
+ const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
1187
+ const SalmonAndTrout = FishEnum.extract(["Salmon", "Trout"]);
1188
+ const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);
1189
+ ```
1190
+
979
1191
  ## Native enums
980
1192
 
981
1193
  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 +1716,49 @@ const myUnion = z.discriminatedUnion("status", [
1504
1716
  myUnion.parse({ status: "success", data: "yippie ki yay" });
1505
1717
  ```
1506
1718
 
1719
+ You can extract a reference to the array of schemas with the `.options` property.
1720
+
1721
+ ```ts
1722
+ myUnion.options; // [ZodObject<...>, ZodObject<...>]
1723
+ ```
1724
+
1725
+ To merge two or more discriminated unions, use `.options` with destructuring.
1726
+
1727
+ ```ts
1728
+ const A = z.discriminatedUnion("status", [
1729
+ /* options */
1730
+ ]);
1731
+ const B = z.discriminatedUnion("status", [
1732
+ /* options */
1733
+ ]);
1734
+
1735
+ const AB = z.discriminatedUnion("status", [...A.options, ...B.options]);
1736
+ ```
1737
+
1507
1738
  ## Records
1508
1739
 
1509
- Record schemas are used to validate types such as `{ [k: string]: number }`.
1740
+ Record schemas are used to validate types such as `Record<string, number>`. This is particularly useful for storing or caching items by ID.
1510
1741
 
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)`:
1742
+ <!-- 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
1743
 
1513
1744
  ```ts
1514
1745
  const NumberCache = z.record(z.number());
1515
1746
 
1516
1747
  type NumberCache = z.infer<typeof NumberCache>;
1517
1748
  // => { [k: string]: number }
1518
- ```
1519
-
1520
- This is particularly useful for storing or caching items by ID.
1749
+ ``` -->
1521
1750
 
1522
1751
  ```ts
1523
- const userSchema = z.object({ name: z.string() });
1524
- const userStoreSchema = z.record(userSchema);
1752
+ const User = z.object({ name: z.string() });
1753
+
1754
+ const UserStore = z.record(z.string(), User);
1755
+ type UserStore = z.infer<typeof UserStore>;
1756
+ // => Record<string, { name: string }>
1757
+ ```
1525
1758
 
1526
- type UserStore = z.infer<typeof userStoreSchema>;
1527
- // => type UserStore = { [ x: string ]: { name: string } }
1759
+ The schema and inferred type can be used like so:
1528
1760
 
1761
+ ```ts
1529
1762
  const userStore: UserStore = {};
1530
1763
 
1531
1764
  userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
@@ -1537,19 +1770,6 @@ userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = {
1537
1770
  }; // TypeError
1538
1771
  ```
1539
1772
 
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
1773
  **A note on numerical keys**
1554
1774
 
1555
1775
  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.
@@ -1775,7 +1995,7 @@ const TestSchema = z.instanceof(Test);
1775
1995
 
1776
1996
  const blob: any = "whatever";
1777
1997
  TestSchema.parse(new Test()); // passes
1778
- TestSchema.parse("blob"); // throws
1998
+ TestSchema.parse(blob); // throws
1779
1999
  ```
1780
2000
 
1781
2001
  ## Functions
@@ -2576,36 +2796,63 @@ type inferred = z.infer<typeof stringToNumber>; // number
2576
2796
 
2577
2797
  ### Writing generic functions
2578
2798
 
2579
- When attempting to write a function that accepts a Zod schema as an input, it's common to try something like this:
2799
+ 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.
2800
+
2801
+ When attempting to write a function that accepts a Zod schema as an input, it's tempting to try something like this:
2580
2802
 
2581
2803
  ```ts
2582
- function makeSchemaOptional<T>(schema: z.ZodType<T>) {
2583
- return schema.optional();
2804
+ function inferSchema<T>(schema: z.ZodType<T>) {
2805
+ return schema;
2584
2806
  }
2585
2807
  ```
2586
2808
 
2587
- This approach has some issues. The `schema` variable in this function is typed as an instance of `ZodType`, which is an abstract class that all Zod schemas inherit from. This approach loses type information, namely _which subclass_ the input actually is.
2809
+ 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
2810
 
2589
2811
  ```ts
2590
- const arg = makeSchemaOptional(z.string());
2591
- arg.unwrap();
2812
+ inferSchema(z.string());
2813
+ // => ZodType<string>
2592
2814
  ```
2593
2815
 
2594
- A better approach is for the generic parameter to refer to _the schema as a whole_.
2816
+ 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`.
2817
+
2818
+ 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
2819
 
2596
2820
  ```ts
2597
- function makeSchemaOptional<T extends z.ZodTypeAny>(schema: T) {
2598
- return schema.optional();
2821
+ function inferSchema<T extends z.ZodTypeAny>(schema: T) {
2822
+ return schema;
2599
2823
  }
2824
+
2825
+ inferSchema(z.string());
2826
+ // => ZodString
2600
2827
  ```
2601
2828
 
2602
2829
  > `ZodTypeAny` is just a shorthand for `ZodType<any, any, any>`, a type that is broad enough to match any Zod schema.
2603
2830
 
2604
- As you can see, `schema` is now fully and properly typed.
2831
+ The Result is now fully and properly typed, and the type system can infer the specific subclass of the schema.
2832
+
2833
+ #### Inferring the inferred type
2834
+
2835
+ 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
2836
 
2606
2837
  ```ts
2607
- const arg = makeSchemaOptional(z.string());
2608
- arg.unwrap(); // ZodString
2838
+ function parseData<T extends z.ZodTypeAny>(data: unknown, schema: T) {
2839
+ return schema.parse(data);
2840
+ }
2841
+
2842
+ parseData("sup", z.string());
2843
+ // => any
2844
+ ```
2845
+
2846
+ 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`.
2847
+
2848
+ ```ts
2849
+ function parseData<T extends z.ZodTypeAny>(data: unknown, schema: T) {
2850
+ return schema.parse(data) as z.infer<T>;
2851
+ // ^^^^^^^^^^^^^^ <- add this
2852
+ }
2853
+
2854
+ parseData("sup", z.string());
2855
+ // => string
2609
2856
  ```
2610
2857
 
2611
2858
  #### Constraining allowable inputs