zod 3.19.1 → 3.20.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
@@ -83,13 +83,15 @@
83
83
  - [Records](#records)
84
84
  - [Maps](#maps)
85
85
  - [Sets](#sets)
86
+ - [Intersections](#intersections)
86
87
  - [Recursive types](#recursive-types)
87
88
  - [JSON type](#json-type)
88
89
  - [Cyclical data](#cyclical-objects)
89
90
  - [Promises](#promises)
90
91
  - [Instanceof](#instanceof)
91
- - [Function schemas](#function-schemas)
92
+ - [Functions](#function-schemas)
92
93
  - [Preprocess](#preprocess)
94
+ - [Custom](#custom)
93
95
  - [Schema methods](#schema-methods)
94
96
  - [.parse](#parse)
95
97
  - [.parseAsync](#parseasync)
@@ -99,6 +101,7 @@
99
101
  - [.superRefine](#superRefine)
100
102
  - [.transform](#transform)
101
103
  - [.default](#default)
104
+ - [.catch](#catch)
102
105
  - [.optional](#optional)
103
106
  - [.nullable](#nullable)
104
107
  - [.nullish](#nullish)
@@ -132,7 +135,7 @@ Some other great aspects:
132
135
  - Zero dependencies
133
136
  - Works in Node.js and all modern browsers
134
137
  - Tiny: 8kb minified + zipped
135
- - Immutable: methods (i.e. `.optional()`) return a new instance
138
+ - Immutable: methods (e.g. `.optional()`) return a new instance
136
139
  - Concise, chainable interface
137
140
  - Functional approach: [parse, don't validate](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/)
138
141
  - Works with plain JavaScript too! You don't need to use TypeScript.
@@ -177,13 +180,22 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
177
180
  <tr>
178
181
  <td align="center">
179
182
  <a href="https://deletype.com/">
180
- <img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="" />
183
+ <img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="Deletype logo" />
181
184
  </a>
182
185
  <br />
183
186
  <b>Deletype</b>
184
187
  <br />
185
188
  <a href="https://deletype.com">deletype.com</a>
186
189
  </td>
190
+ <td align="center">
191
+ <a href="https://proxy.com/">
192
+ <img src="https://avatars.githubusercontent.com/u/14321439?s=200&v=4" width="200px;" alt="Proxy logo" />
193
+ </a>
194
+ <br />
195
+ <b>Proxy</b>
196
+ <br />
197
+ <a href="https://proxy.com">proxy.com</a>
198
+ </td>
187
199
  </tr>
188
200
  </table>
189
201
 
@@ -191,16 +203,27 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
191
203
 
192
204
  <table>
193
205
  <tr>
206
+ <td align="center" colspan="2">
207
+ <a href="https://www.numeric.io">
208
+ <img src="https://i.imgur.com/kTiLtZt.png" width="250px;" alt="Numeric logo" />
209
+ </a>
210
+ <br />
211
+ <b>Numeric</b>
212
+ <br />
213
+ <a href="https://www.numeric.io">numeric.io</a>
214
+ </td>
194
215
  <td align="center">
195
216
  <a href="https://snaplet.dev">
196
- <img src="https://avatars.githubusercontent.com/u/69029941?s=200&v=4" width="150px;" alt="" />
217
+ <img src="https://avatars.githubusercontent.com/u/69029941?s=200&v=4" width="150px;" alt="Snaplet logo" />
197
218
  </a>
198
219
  <br />
199
220
  <b>Snaplet</b>
200
221
  <br />
201
222
  <a href="https://snaplet.dev">snaplet.dev</a>
202
223
  </td>
203
- <td align="center">
224
+ </tr>
225
+ <tr>
226
+ <td align="center">
204
227
  <a href="https://marcatopartners.com/">
205
228
  <img src="https://avatars.githubusercontent.com/u/84106192?s=200&v=4" width="150px;" alt="Marcato Partners" />
206
229
  </a>
@@ -210,14 +233,14 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
210
233
  <a href="https://marcatopartners.com/">marcatopartners.com</a>
211
234
  </td>
212
235
  <td align="center">
213
- <a href="https://github.com/macandcheese-spaghetticode">
214
- <img src="https://avatars.githubusercontent.com/u/76997592?v=4" width="150px;" alt="Trip" />
236
+ <a href="https://interval.com">
237
+ <img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4" width="150px;" alt="" />
215
238
  </a>
216
239
  <br />
217
- <b>Trip</b>
240
+ <b>Interval</b>
241
+ <br />
242
+ <a href="https://interval.com">interval.com</a>
218
243
  </td>
219
- </tr>
220
- <tr>
221
244
  <td align="center">
222
245
  <a href="https://seasoned.cc">
223
246
  <img src="https://avatars.githubusercontent.com/u/33913103?s=200&v=4" width="150px;" alt="" />
@@ -227,14 +250,16 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
227
250
  <br />
228
251
  <a href="https://seasoned.cc">seasoned.cc</a>
229
252
  </td>
253
+ </tr>
254
+ <tr>
230
255
  <td align="center">
231
- <a href="https://interval.com">
232
- <img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4" width="150px;" alt="" />
256
+ <a href="https://www.bamboocreative.nz/">
257
+ <img src="https://avatars.githubusercontent.com/u/41406870?v=4" width="150px;" alt="Bamboo Creative logo" />
233
258
  </a>
234
259
  <br />
235
- <b>Interval</b>
260
+ <b>Bamboo Creative</b>
236
261
  <br />
237
- <a href="https://interval.com">interval.com</a>
262
+ <a href="https://www.bamboocreative.nz">bamboocreative.nz</a>
238
263
  </td>
239
264
  </tr>
240
265
  </table>
@@ -275,6 +300,16 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
275
300
  </td>
276
301
  </tr>
277
302
  <tr>
303
+ <td align="center">
304
+ <a href="https://fungible.systems/">
305
+ <img src="https://avatars.githubusercontent.com/u/80220121?s=200&v=4" width="100px;" alt="Fungible Systems logo"/>
306
+ </a>
307
+ <br />
308
+ <b>Fungible Systems</b>
309
+ <br/>
310
+ <a href="https://fungible.systems/">fungible.systems</a>
311
+ <br />
312
+ </td>
278
313
  <td align="center">
279
314
  <a href="https://adaptable.io/">
280
315
  <img src="https://avatars.githubusercontent.com/u/60378268?s=200&v=4" width="100px;" alt=""/>
@@ -303,46 +338,70 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
303
338
 
304
339
  There are a growing number of tools that are built atop or support Zod natively! If you've built a tool or library on top of Zod, tell me about it [on Twitter](https://twitter.com/colinhacks) or [start a Discussion](https://github.com/colinhacks/zod/discussions). I'll add it below and tweet it out.
305
340
 
341
+ #### Resources
342
+
343
+ - [Total TypeScript Zod Tutorial](https://www.totaltypescript.com/tutorials/zod) by [@mattpocockuk](https://twitter.com/mattpocockuk)
344
+ - [Fixing TypeScript's Blindspot: Runtime Typechecking](https://www.youtube.com/watch?v=rY_XqfSHock) by [@jherr](https://twitter.com/jherr)
345
+
346
+ #### API libraries
347
+
306
348
  - [`tRPC`](https://github.com/trpc/trpc): Build end-to-end typesafe APIs without GraphQL.
307
- - [`ts-to-zod`](https://github.com/fabien0102/ts-to-zod): Convert TypeScript definitions into Zod schemas.
308
- - [`zod-to-ts`](https://github.com/sachinraja/zod-to-ts): Generate TypeScript definitions from Zod schemas.
309
- - [`@anatine/zod-openapi`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-openapi): Converts a Zod schema to an OpenAPI v3.x `SchemaObject`.
310
- - [`@anatine/zod-mock`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-mock): Generate mock data from a Zod schema. Powered by [faker.js](https://github.com/Marak/Faker.js).
311
349
  - [`@anatine/zod-nestjs`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-nestjs): Helper methods for using Zod in a NestJS project.
312
- - [`zod-mocking`](https://github.com/dipasqualew/zod-mocking): Generate mock data from your Zod schemas.
313
- - [`zod-fast-check`](https://github.com/DavidTimms/zod-fast-check): Generate `fast-check` arbitraries from Zod schemas.
314
350
  - [`zod-endpoints`](https://github.com/flock-community/zod-endpoints): Contract-first strictly typed endpoints with Zod. OpenAPI compatible.
351
+ - [`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.
352
+ - [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
315
353
  - [`express-zod-api`](https://github.com/RobinTail/express-zod-api): Build Express-based APIs with I/O schema validation and custom middlewares.
354
+
355
+ #### Form integrations
356
+
357
+ - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form.
358
+ - [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s
359
+ - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod.
360
+ - [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod.
361
+ - [`zodix`](https://github.com/rileytomasek/zodix): Zod utilities for FormData and URLSearchParams in Remix loaders and actions.
362
+ - [`formik-validator-zod`](https://github.com/glazy/formik-validator-zod): Formik-compliant validator library that simplifies using Zod with Formik.
363
+ - [`zod-i18n-map`](https://github.com/aiji42/zod-i18n): Useful for translating Zod error messages.
364
+
365
+ #### Zod to X
366
+
367
+ - [`zod-to-ts`](https://github.com/sachinraja/zod-to-ts): Generate TypeScript definitions from Zod schemas.
316
368
  - [`zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema): Convert your Zod schemas into [JSON Schemas](https://json-schema.org/).
369
+ - [`@anatine/zod-openapi`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-openapi): Converts a Zod schema to an OpenAPI v3.x `SchemaObject`.
370
+ - [`zod-fast-check`](https://github.com/DavidTimms/zod-fast-check): Generate `fast-check` arbitraries from Zod schemas.
371
+ - [`zod-dto`](https://github.com/kbkk/abitia/tree/master/packages/zod-dto): Generate Nest.js DTOs from a Zod schema.
372
+ - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas.
373
+ - [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters.
374
+ - [`nestjs-graphql-zod`](https://github.com/incetarik/nestjs-graphql-zod): Generates NestJS GraphQL model classes from Zod schemas. Provides GraphQL method decorators working with Zod schemas.
375
+
376
+ #### X to Zod
377
+
378
+ - [`ts-to-zod`](https://github.com/fabien0102/ts-to-zod): Convert TypeScript definitions into Zod schemas.
379
+ - [`@runtyping/zod`](https://github.com/johngeorgewright/runtyping/tree/master/packages/zod): Generate Zod from static types & JSON schema.
317
380
  - [`json-schema-to-zod`](https://github.com/StefanTerdell/json-schema-to-zod): Convert your [JSON Schemas](https://json-schema.org/) into Zod schemas. [Live demo](https://StefanTerdell.github.io/json-schema-to-zod-react/).
318
381
  - [`json-to-zod`](https://github.com/rsinohara/json-to-zod): Convert JSON objects into Zod schemas. [Live demo](https://rsinohara.github.io/json-to-zod-react/).
319
- - [`zod-dto`](https://github.com/kbkk/abitia/tree/master/packages/zod-dto): Generate Nest.js DTOs from a Zod schema.
320
- - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
321
382
  - [`graphql-codegen-typescript-validation-schema`](https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema): GraphQL Code Generator plugin to generate form validation schema from your GraphQL schema
322
383
  - [`zod-prisma`](https://github.com/CarterGrimmeisen/zod-prisma): Generate Zod schemas from your Prisma schema.
323
- - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas
324
- - [`Supervillain`](https://github.com/Southclaws/supervillain): Generate Zod schemas from your Go structs
325
- - [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters
384
+ - [`Supervillain`](https://github.com/Southclaws/supervillain): Generate Zod schemas from your Go structs.
326
385
  - [`prisma-zod-generator`](https://github.com/omar-dulaimi/prisma-zod-generator): Emit Zod schemas from your Prisma schema.
327
386
  - [`prisma-trpc-generator`](https://github.com/omar-dulaimi/prisma-trpc-generator): Emit fully implemented tRPC routers and their validation schemas using Zod.
328
- - [`nestjs-graphql-zod`](https://github.com/incetarik/nestjs-graphql-zod): Generates NestJS GraphQL model classes from Zod schemas dynamically and provides GraphQL method decorators working with Zod schemas.
329
- - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
330
- - [`remix-domains`](https://github.com/SeasonedSoftware/remix-domains/): Improves end-to-end type safety in [Remix](https://remix.run/) by leveraging Zod to parse the framework's inputs such as FormData, URLSearchParams, etc.
331
- - [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
332
- - [`@runtyping/zod`](https://github.com/johngeorgewright/runtyping/tree/master/packages/zod): Generate zod from static types & JSON schema.
333
- - [`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
334
387
 
335
- #### Form integrations
388
+ #### Mocking
389
+
390
+ - [`@anatine/zod-mock`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-mock): Generate mock data from a Zod schema. Powered by [faker.js](https://github.com/Marak/Faker.js).
391
+ - [`zod-mocking`](https://github.com/dipasqualew/zod-mocking): Generate mock data from your Zod schemas.
336
392
 
337
- - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form
338
- - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod
339
- - [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod
393
+ #### Powered by Zod
394
+
395
+ - [`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.
396
+ - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
397
+ - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
398
+ - [`znv`](https://github.com/lostfictions/znv): Type-safe environment parsing and validation for Node.js with Zod schemas
340
399
 
341
400
  ## Installation
342
401
 
343
402
  ### Requirements
344
403
 
345
- - TypeScript 4.1+!
404
+ - TypeScript 4.5+!
346
405
  - You must enable `strict` mode in your `tsconfig.json`. This is a best practice for all TypeScript projects.
347
406
 
348
407
  ```ts
@@ -356,17 +415,16 @@ There are a growing number of tools that are built atop or support Zod natively!
356
415
  }
357
416
  ```
358
417
 
359
- ### Node/npm
360
-
361
- To install Zod v3:
418
+ ### From `npm` (Node/Bun)
362
419
 
363
420
  ```sh
364
421
  npm install zod # npm
365
422
  yarn add zod # yarn
423
+ bun add zod # bun
366
424
  pnpm add zod # pnpm
367
425
  ```
368
426
 
369
- ### Deno
427
+ ### From `deno.land/x` (Deno)
370
428
 
371
429
  Unlike Node, Deno relies on direct URL imports instead of a package manager like NPM. Zod is available on [deno.land/x](https://deno.land/x). The latest version can be imported like so:
372
430
 
@@ -428,6 +486,7 @@ z.number();
428
486
  z.bigint();
429
487
  z.boolean();
430
488
  z.date();
489
+ z.symbol();
431
490
 
432
491
  // empty types
433
492
  z.undefined();
@@ -449,8 +508,12 @@ z.never();
449
508
  ```ts
450
509
  const tuna = z.literal("tuna");
451
510
  const twelve = z.literal(12);
511
+ const twobig = z.literal(2n); // bigint literal
452
512
  const tru = z.literal(true);
453
513
 
514
+ const terrificSymbol = Symbol("terrific");
515
+ const terrific = z.literal(terrificSymbol);
516
+
454
517
  // retrieve literal value
455
518
  tuna.value; // "tuna"
456
519
  ```
@@ -472,18 +535,11 @@ z.string().cuid();
472
535
  z.string().regex(regex);
473
536
  z.string().startsWith(string);
474
537
  z.string().endsWith(string);
475
-
476
- // trim whitespace
477
- z.string().trim();
478
-
479
- // deprecated, equivalent to .min(1)
480
- z.string().nonempty();
481
-
482
- // optional custom error message
483
- z.string().nonempty({ message: "Can't be empty" });
538
+ z.string().trim(); // trim whitespace
539
+ z.string().datetime(); // defaults to UTC, see below for options
484
540
  ```
485
541
 
486
- > Check out [validator.js](https://github.com/validatorjs/validator.js) for a bunch of other useful string validation functions.
542
+ > 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).
487
543
 
488
544
  You can customize some common error messages when creating a string schema.
489
545
 
@@ -505,6 +561,67 @@ z.string().url({ message: "Invalid url" });
505
561
  z.string().uuid({ message: "Invalid UUID" });
506
562
  z.string().startsWith("https://", { message: "Must provide secure URL" });
507
563
  z.string().endsWith(".com", { message: "Only .com domains allowed" });
564
+ z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
565
+ ```
566
+
567
+ ## Coercion for primitives
568
+
569
+ Zod now provides a more convenient way to coerce primitive values.
570
+
571
+ ```ts
572
+ const schema = z.coerce.string();
573
+ schema.parse("tuna"); // => "tuna"
574
+ schema.parse(12); // => "12"
575
+ schema.parse(true); // => "true"
576
+ ```
577
+
578
+ 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.
579
+
580
+ ```ts
581
+ z.coerce.string().email().min(5);
582
+ ```
583
+
584
+ All primitive types support coercion.
585
+
586
+ ```ts
587
+ z.coerce.string(); // String(input)
588
+ z.coerce.number(); // Number(input)
589
+ z.coerce.boolean(); // Boolean(input)
590
+ z.coerce.bigint(); // BigInt(input)
591
+ z.coerce.date(); // new Date(input)
592
+ ```
593
+
594
+ ### Datetime validation
595
+
596
+ The `z.string().datetime()` method defaults to UTC validation: no timezone offsets with arbitrary sub-second decimal precision.
597
+
598
+ ```ts
599
+ const datetime = z.string().datetime();
600
+
601
+ datetime.parse("2020-01-01T00:00:00Z"); // pass
602
+ datetime.parse("2020-01-01T00:00:00.123Z"); // pass
603
+ datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
604
+ datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)
605
+ ```
606
+
607
+ Timezone offsets can be allowed by setting the `offset` option to `true`.
608
+
609
+ ```ts
610
+ const datetime = z.string().datetime({ offset: true });
611
+
612
+ datetime.parse("2020-01-01T00:00:00+02:00"); // pass
613
+ datetime.parse("2020-01-01T00:00:00.123+02:00"); // pass (millis optional)
614
+ datetime.parse("2020-01-01T00:00:00Z"); // pass (Z still supported)
615
+ ```
616
+
617
+ You can additionally constrain the allowable `precision`. By default, arbitrary sub-second precision is supported (but optional).
618
+
619
+ ```ts
620
+ const datetime = z.string().datetime({ precision: 3 });
621
+
622
+ datetime.parse("2020-01-01T00:00:00.123Z"); // pass
623
+ datetime.parse("2020-01-01T00:00:00Z"); // fail
624
+ datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
508
625
  ```
509
626
 
510
627
  ## Numbers
@@ -534,6 +651,8 @@ z.number().negative(); // < 0
534
651
  z.number().nonpositive(); // <= 0
535
652
 
536
653
  z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)
654
+
655
+ z.number().finite(); // value must be finite, not Infinity or -Infinity
537
656
  ```
538
657
 
539
658
  Optionally, you can pass in a second argument to provide a custom error message.
@@ -758,7 +877,7 @@ nullableString.parse(null); // => null
758
877
  Or use the `.nullable()` method.
759
878
 
760
879
  ```ts
761
- const E = z.string().nullable(); // equivalent to D
880
+ const E = z.string().nullable(); // equivalent to nullableString
762
881
  type E = z.infer<typeof E>; // string | null
763
882
  ```
764
883
 
@@ -927,6 +1046,41 @@ const deepPartialUser = user.deepPartial();
927
1046
 
928
1047
  > Important limitation: deep partials only work as expected in hierarchies of objects, arrays, and tuples.
929
1048
 
1049
+ ### `.required`
1050
+
1051
+ Contrary to the `.partial` method, the `.required` method makes all properties required.
1052
+
1053
+ Starting from this object:
1054
+
1055
+ ```ts
1056
+ const user = z.object({
1057
+ email: z.string()
1058
+ username: z.string(),
1059
+ }).partial();
1060
+ // { email?: string | undefined; username?: string | undefined }
1061
+ ```
1062
+
1063
+ We can create a required version:
1064
+
1065
+ ```ts
1066
+ const requiredUser = user.required();
1067
+ // { email: string; username: string }
1068
+ ```
1069
+
1070
+ You can also specify which properties to make required:
1071
+
1072
+ ```ts
1073
+ const requiredEmail = user.required({
1074
+ email: true,
1075
+ });
1076
+ /*
1077
+ {
1078
+ email: string;
1079
+ username?: string | undefined;
1080
+ }
1081
+ */
1082
+ ```
1083
+
930
1084
  ### `.passthrough`
931
1085
 
932
1086
  By default Zod object schemas strip out unrecognized keys during parsing.
@@ -1103,21 +1257,25 @@ const stringOrNumber = z.string().or(z.number());
1103
1257
 
1104
1258
  ## Discriminated unions
1105
1259
 
1106
- If the union consists of object schemas all identifiable by a common property, it is possible to use
1107
- the `z.discriminatedUnion` method.
1260
+ A discriminated union is a union of object schemas that all share a particular key.
1261
+
1262
+ ```ts
1263
+ type MyUnion =
1264
+ | { status: "success"; data: string }
1265
+ | { status: "failed"; error: Error };
1266
+ ```
1108
1267
 
1109
- The advantage is in more efficient evaluation and more human friendly errors. With the basic union method the input is
1110
- tested against each of the provided "options", and in the case of invalidity, issues for all the "options" are shown in
1111
- the zod error. On the other hand, the discriminated union allows for selecting just one of the "options", testing
1112
- against it, and showing only the issues related to this "option".
1268
+ Such unions can be represented with the `z.discriminatedUnion` method. This enables faster evaluation, because Zod can check the _discriminator key_ (`status` in the example above) to determine which schema should be used to parse the input. This makes parsing more efficient and lets Zod report friendlier errors.
1269
+
1270
+ With the basic union method the input is tested against each of the provided "options", and in the case of invalidity, issues for all the "options" are shown in the zod error. On the other hand, the discriminated union allows for selecting just one of the "options", testing against it, and showing only the issues related to this "option".
1113
1271
 
1114
1272
  ```ts
1115
- const item = z
1116
- .discriminatedUnion("type", [
1117
- z.object({ type: z.literal("a"), a: z.string() }),
1118
- z.object({ type: z.literal("b"), b: z.string() }),
1119
- ])
1120
- .parse({ type: "a", a: "abc" });
1273
+ const myUnion = z.discriminatedUnion("status", [
1274
+ z.object({ status: z.literal("success"), data: z.string() }),
1275
+ z.object({ status: z.literal("failed"), error: z.instanceof(Error) }),
1276
+ ]);
1277
+
1278
+ myUnion.parse({ type: "success", data: "yippie ki yay" });
1121
1279
  ```
1122
1280
 
1123
1281
  ## Records
@@ -1396,6 +1554,7 @@ const myFunction = z
1396
1554
  .function()
1397
1555
  .args(z.string(), z.number()) // accepts an arbitrary number of arguments
1398
1556
  .returns(z.boolean());
1557
+
1399
1558
  type myFunction = z.infer<typeof myFunction>;
1400
1559
  // => (arg0: string, arg1: number)=>boolean
1401
1560
  ```
@@ -1437,8 +1596,9 @@ const myFunction = z
1437
1596
  .function()
1438
1597
  .args(z.string())
1439
1598
  .implement((arg) => {
1440
- return [arg.length]; //
1599
+ return [arg.length];
1441
1600
  });
1601
+
1442
1602
  myFunction; // (arg: string)=>number[]
1443
1603
  ```
1444
1604
 
@@ -1459,6 +1619,8 @@ myFunction.returnType();
1459
1619
 
1460
1620
  ## Preprocess
1461
1621
 
1622
+ > Zod now supports primitive coercion without the need for `.preprocess()`. See the [coercion docs](#coercion-for-primitives) for more information.
1623
+
1462
1624
  Typically Zod operates under a "parse then transform" paradigm. Zod validates the input first, then passes it through a chain of transformation functions. (For more information about transforms, read the [.transform docs](#transform).)
1463
1625
 
1464
1626
  But sometimes you want to apply some transform to the input _before_ parsing happens. A common use case: type coercion. Zod enables this with the `z.preprocess()`.
@@ -1469,6 +1631,22 @@ const castToString = z.preprocess((val) => String(val), z.string());
1469
1631
 
1470
1632
  This returns a `ZodEffects` instance. `ZodEffects` is a wrapper class that contains all logic pertaining to preprocessing, refinements, and transforms.
1471
1633
 
1634
+ ## Custom schemas
1635
+
1636
+ You can create a Zod schema for any TypeScript type by using `z.custom()`. This is useful for creating schemas for types that are not supported by Zod out of the box, such as template string literals.
1637
+
1638
+ ```ts
1639
+ const px = z.custom<`${number}px`>((val) => /^\d+px$/.test(val));
1640
+ px.parse("100px"); // pass
1641
+ px.parse("100vw"); // fail
1642
+ ```
1643
+
1644
+ If you don't provide a validation function, Zod will allow any value. This can be dangerous!
1645
+
1646
+ ```ts
1647
+ z.custom<{ arg: string }>(); // performs no validation
1648
+ ```
1649
+
1472
1650
  ## Schema methods
1473
1651
 
1474
1652
  All Zod schemas contain certain methods.
@@ -1483,6 +1661,7 @@ Given any Zod schema, you can call its `.parse` method to check `data` is valid.
1483
1661
 
1484
1662
  ```ts
1485
1663
  const stringSchema = z.string();
1664
+
1486
1665
  stringSchema.parse("fish"); // => returns "fish"
1487
1666
  stringSchema.parse(12); // throws Error('Non-string type: number');
1488
1667
  ```
@@ -1586,7 +1765,7 @@ type RefineParams = {
1586
1765
  For advanced cases, the second argument can also be a function that returns `RefineParams`/
1587
1766
 
1588
1767
  ```ts
1589
- z.string().refine(
1768
+ const longString = z.string().refine(
1590
1769
  (val) => val.length > 10,
1591
1770
  (val) => ({ message: `${val} is not more than 10 characters` })
1592
1771
  );
@@ -1603,8 +1782,9 @@ const passwordForm = z
1603
1782
  .refine((data) => data.password === data.confirm, {
1604
1783
  message: "Passwords don't match",
1605
1784
  path: ["confirm"], // path of error
1606
- })
1607
- .parse({ password: "asdf", confirm: "qwer" });
1785
+ });
1786
+
1787
+ passwordForm.parse({ password: "asdf", confirm: "qwer" });
1608
1788
  ```
1609
1789
 
1610
1790
  Because you provided a `path` parameter, the resulting error will be:
@@ -1644,7 +1824,6 @@ z.string()
1644
1824
 
1645
1825
  <!-- Note that the `path` is set to `["confirm"]` , so you can easily display this error underneath the "Confirm password" textbox.
1646
1826
 
1647
-
1648
1827
  ```ts
1649
1828
  const allForms = z.object({ passwordForm }).parse({
1650
1829
  passwordForm: {
@@ -1721,12 +1900,40 @@ const schema = z.number().superRefine((val, ctx) => {
1721
1900
  });
1722
1901
  ```
1723
1902
 
1903
+ #### Type refinements
1904
+
1905
+ If you provide a [type predicate](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) to `.refine()` or `superRefine()`, the resulting type will be narrowed down to your predicate's type. This is useful if you are mixing multiple chained refinements and transformations:
1906
+
1907
+ ```ts
1908
+ const schema = z
1909
+ .object({
1910
+ first: z.string(),
1911
+ second: z.number(),
1912
+ })
1913
+ .nullable()
1914
+ .superRefine((arg, ctx): arg is { first: string; second: number } => {
1915
+ if (!arg) {
1916
+ ctx.addIssue({
1917
+ code: z.ZodIssueCode.custom, // customize your issue
1918
+ message: "object should exist",
1919
+ });
1920
+ return false;
1921
+ }
1922
+ return true;
1923
+ })
1924
+ // here, TS knows that arg is not null
1925
+ .refine((arg) => arg.first === "bob", "`first` is not `bob`!");
1926
+ ```
1927
+
1928
+ > ⚠️ You must **still** call `ctx.addIssue()` if using `superRefine()` with a type predicate function. Otherwise the refinement won't be validated.
1929
+
1724
1930
  ### `.transform`
1725
1931
 
1726
1932
  To transform data after parsing, use the `transform` method.
1727
1933
 
1728
1934
  ```ts
1729
1935
  const stringToNumber = z.string().transform((val) => val.length);
1936
+
1730
1937
  stringToNumber.parse("string"); // => 6
1731
1938
  ```
1732
1939
 
@@ -1773,7 +1980,7 @@ const Strings = z.string().transform((val, ctx) => {
1773
1980
  Transforms and refinements can be interleaved. These will be executed in the order they are declared.
1774
1981
 
1775
1982
  ```ts
1776
- z.string()
1983
+ const nameToGreeting = z.string()
1777
1984
  .transform((val) => val.toUpperCase())
1778
1985
  .refine((val) => val.length > 15)
1779
1986
  .transform((val) => `Hello ${val}`)
@@ -1815,6 +2022,37 @@ numberWithRandomDefault.parse(undefined); // => 0.1871840107401901
1815
2022
  numberWithRandomDefault.parse(undefined); // => 0.7223408162401552
1816
2023
  ```
1817
2024
 
2025
+ Conceptually, this is how Zod processes default values:
2026
+
2027
+ 1. If the input is `undefined`, the default value is returned
2028
+ 2. Otherwise, the data is parsed using the base schema
2029
+
2030
+ ### `.catch`
2031
+
2032
+ Use `.catch()` to provide a "catch value" to be returned in the event of a parsing error.
2033
+
2034
+ ```ts
2035
+ const numberWithCatch = z.number().catch(42);
2036
+
2037
+ numberWithCatch.parse(5); // => 5
2038
+ numberWithCatch.parse("tuna"); // => 42
2039
+ ```
2040
+
2041
+ Optionally, you can pass a function into `.catch` that will be re-executed whenever a default value needs to be generated:
2042
+
2043
+ ```ts
2044
+ const numberWithRandomCatch = z.number().catch(Math.random);
2045
+
2046
+ numberWithRandomDefault.parse("sup"); // => 0.4413456736055323
2047
+ numberWithRandomDefault.parse("sup"); // => 0.1871840107401901
2048
+ numberWithRandomDefault.parse("sup"); // => 0.7223408162401552
2049
+ ```
2050
+
2051
+ Conceptually, this is how Zod processes "catch values":
2052
+
2053
+ 1. The data is parsed using the base schema
2054
+ 2. If the parsing fails, the "catch value" is returned
2055
+
1818
2056
  ### `.optional`
1819
2057
 
1820
2058
  A convenience method that returns an optional version of a schema.
@@ -1853,7 +2091,7 @@ z.string().optional().nullable();
1853
2091
  A convenience method that returns an array schema for the given type:
1854
2092
 
1855
2093
  ```ts
1856
- const nullableString = z.string().array(); // string[]
2094
+ const stringArray = z.string().array(); // string[]
1857
2095
 
1858
2096
  // equivalent to
1859
2097
  z.array(z.string());
@@ -1875,7 +2113,7 @@ z.promise(z.string());
1875
2113
  A convenience method for union types.
1876
2114
 
1877
2115
  ```ts
1878
- z.string().or(z.number()); // string | number
2116
+ const stringOrNumber = z.string().or(z.number()); // string | number
1879
2117
 
1880
2118
  // equivalent to
1881
2119
  z.union([z.string(), z.number()]);
@@ -1886,7 +2124,7 @@ z.union([z.string(), z.number()]);
1886
2124
  A convenience method for creating intersection types.
1887
2125
 
1888
2126
  ```ts
1889
- z.object({ name: z.string() }).and(z.object({ age: z.number() })); // { name: string } & { age: number }
2127
+ const nameAndAge = z.object({ name: z.string() }).and(z.object({ age: z.number() })); // { name: string } & { age: number }
1890
2128
 
1891
2129
  // equivalent to
1892
2130
  z.intersection(z.object({ name: z.string() }), z.object({ age: z.number() }));
@@ -1910,7 +2148,7 @@ petCat(fido); // works fine
1910
2148
  In some cases, its can be desirable to simulate _nominal typing_ inside TypeScript. For instance, you may wish to write a function that only accepts an input that has been validated by Zod. This can be achieved with _branded types_ (AKA _opaque types_).
1911
2149
 
1912
2150
  ```ts
1913
- const Cat = z.object({ name: z.string }).brand<"Cat">();
2151
+ const Cat = z.object({ name: z.string() }).brand<"Cat">();
1914
2152
  type Cat = z.infer<typeof Cat>;
1915
2153
 
1916
2154
  const petCat = (cat: Cat) => {};
@@ -1926,7 +2164,7 @@ petCat({ name: "fido" });
1926
2164
  Under the hood, this works by attaching a "brand" to the inferred type using an intersection type. This way, plain/unbranded data structures are no longer assignable to the inferred type of the schema.
1927
2165
 
1928
2166
  ```ts
1929
- const Cat = z.object({ name: z.string }).brand<"Cat">();
2167
+ const Cat = z.object({ name: z.string() }).brand<"Cat">();
1930
2168
  type Cat = z.infer<typeof Cat>;
1931
2169
  // {name: string} & {[symbol]: "Cat"}
1932
2170
  ```
@@ -1966,7 +2204,7 @@ type inferred = z.infer<typeof stringToNumber>; // number
1966
2204
 
1967
2205
  ### Writing generic functions
1968
2206
 
1969
- When attempting to write a functions that accepts a Zod schemas as an input, it's common to try something like this:
2207
+ When attempting to write a function that accepts a Zod schema as an input, it's common to try something like this:
1970
2208
 
1971
2209
  ```ts
1972
2210
  function makeSchemaOptional<T>(schema: z.ZodType<T>) {
@@ -1981,7 +2219,7 @@ const arg = makeSchemaOptional(z.string());
1981
2219
  arg.unwrap();
1982
2220
  ```
1983
2221
 
1984
- A better approach is for the generate parameter to refer to _the schema as a whole_.
2222
+ A better approach is for the generic parameter to refer to _the schema as a whole_.
1985
2223
 
1986
2224
  ```ts
1987
2225
  function makeSchemaOptional<T extends z.ZodTypeAny>(schema: T) {
@@ -2051,6 +2289,8 @@ if (!data.success) {
2051
2289
 
2052
2290
  > For detailed information about the possible error codes and how to customize error messages, check out the dedicated error handling guide: [ERROR_HANDLING.md](ERROR_HANDLING.md)
2053
2291
 
2292
+ Zod's error reporting emphasizes _completeness_ and _correctness_. If you are looking to present a useful error message to the end user, you should either override Zod's error messages using an error map (described in detail in the Error Handling guide) or use a third party library like [`zod-validation-error`](https://github.com/causaly/zod-validation-error)
2293
+
2054
2294
  ### Error formatting
2055
2295
 
2056
2296
  You can use the `.format()` method to convert this error into a nested object.