zod 3.19.1 → 3.20.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 +250 -63
- package/lib/.eslintrc.d.ts +43 -0
- package/lib/.eslintrc.js +67 -0
- package/lib/ZodError.d.ts +13 -9
- package/lib/ZodError.js +1 -0
- package/lib/helpers/errorUtil.d.ts +2 -6
- package/lib/helpers/parseUtil.js +3 -3
- package/lib/helpers/typeAliases.d.ts +1 -1
- package/lib/helpers/util.js +2 -0
- package/lib/index.mjs +354 -32
- package/lib/index.umd.js +359 -31
- package/lib/locales/en.js +3 -0
- package/lib/types.d.ts +246 -64
- package/lib/types.js +432 -117
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@
|
|
|
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)
|
|
@@ -99,6 +100,7 @@
|
|
|
99
100
|
- [.superRefine](#superRefine)
|
|
100
101
|
- [.transform](#transform)
|
|
101
102
|
- [.default](#default)
|
|
103
|
+
- [.catch](#catch)
|
|
102
104
|
- [.optional](#optional)
|
|
103
105
|
- [.nullable](#nullable)
|
|
104
106
|
- [.nullish](#nullish)
|
|
@@ -177,13 +179,22 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
177
179
|
<tr>
|
|
178
180
|
<td align="center">
|
|
179
181
|
<a href="https://deletype.com/">
|
|
180
|
-
<img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="" />
|
|
182
|
+
<img src="https://avatars0.githubusercontent.com/u/15068039?s=200&v=4" width="200px;" alt="Deletype logo" />
|
|
181
183
|
</a>
|
|
182
184
|
<br />
|
|
183
185
|
<b>Deletype</b>
|
|
184
186
|
<br />
|
|
185
187
|
<a href="https://deletype.com">deletype.com</a>
|
|
186
188
|
</td>
|
|
189
|
+
<td align="center">
|
|
190
|
+
<a href="https://proxy.com/">
|
|
191
|
+
<img src="https://avatars.githubusercontent.com/u/14321439?s=200&v=4" width="200px;" alt="Proxy logo" />
|
|
192
|
+
</a>
|
|
193
|
+
<br />
|
|
194
|
+
<b>Proxy</b>
|
|
195
|
+
<br />
|
|
196
|
+
<a href="https://proxy.com">proxy.com</a>
|
|
197
|
+
</td>
|
|
187
198
|
</tr>
|
|
188
199
|
</table>
|
|
189
200
|
|
|
@@ -191,16 +202,27 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
191
202
|
|
|
192
203
|
<table>
|
|
193
204
|
<tr>
|
|
205
|
+
<td align="center" colspan="2">
|
|
206
|
+
<a href="https://www.numeric.io">
|
|
207
|
+
<img src="https://i.imgur.com/kTiLtZt.png" width="250px;" alt="Numeric logo" />
|
|
208
|
+
</a>
|
|
209
|
+
<br />
|
|
210
|
+
<b>Numeric</b>
|
|
211
|
+
<br />
|
|
212
|
+
<a href="https://www.numeric.io">numeric.io</a>
|
|
213
|
+
</td>
|
|
194
214
|
<td align="center">
|
|
195
215
|
<a href="https://snaplet.dev">
|
|
196
|
-
<img src="https://avatars.githubusercontent.com/u/69029941?s=200&v=4" width="150px;" alt="" />
|
|
216
|
+
<img src="https://avatars.githubusercontent.com/u/69029941?s=200&v=4" width="150px;" alt="Snaplet logo" />
|
|
197
217
|
</a>
|
|
198
218
|
<br />
|
|
199
219
|
<b>Snaplet</b>
|
|
200
220
|
<br />
|
|
201
221
|
<a href="https://snaplet.dev">snaplet.dev</a>
|
|
202
222
|
</td>
|
|
203
|
-
|
|
223
|
+
</tr>
|
|
224
|
+
<tr>
|
|
225
|
+
<td align="center">
|
|
204
226
|
<a href="https://marcatopartners.com/">
|
|
205
227
|
<img src="https://avatars.githubusercontent.com/u/84106192?s=200&v=4" width="150px;" alt="Marcato Partners" />
|
|
206
228
|
</a>
|
|
@@ -210,14 +232,14 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
210
232
|
<a href="https://marcatopartners.com/">marcatopartners.com</a>
|
|
211
233
|
</td>
|
|
212
234
|
<td align="center">
|
|
213
|
-
<a href="https://
|
|
214
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
235
|
+
<a href="https://interval.com">
|
|
236
|
+
<img src="https://avatars.githubusercontent.com/u/67802063?s=200&v=4" width="150px;" alt="" />
|
|
215
237
|
</a>
|
|
216
238
|
<br />
|
|
217
|
-
<b>
|
|
239
|
+
<b>Interval</b>
|
|
240
|
+
<br />
|
|
241
|
+
<a href="https://interval.com">interval.com</a>
|
|
218
242
|
</td>
|
|
219
|
-
</tr>
|
|
220
|
-
<tr>
|
|
221
243
|
<td align="center">
|
|
222
244
|
<a href="https://seasoned.cc">
|
|
223
245
|
<img src="https://avatars.githubusercontent.com/u/33913103?s=200&v=4" width="150px;" alt="" />
|
|
@@ -227,14 +249,16 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
227
249
|
<br />
|
|
228
250
|
<a href="https://seasoned.cc">seasoned.cc</a>
|
|
229
251
|
</td>
|
|
252
|
+
</tr>
|
|
253
|
+
<tr>
|
|
230
254
|
<td align="center">
|
|
231
|
-
<a href="https://
|
|
232
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
255
|
+
<a href="https://www.bamboocreative.nz/">
|
|
256
|
+
<img src="https://avatars.githubusercontent.com/u/41406870?v=4" width="150px;" alt="Bamboo Creative logo" />
|
|
233
257
|
</a>
|
|
234
258
|
<br />
|
|
235
|
-
<b>
|
|
259
|
+
<b>Bamboo Creative</b>
|
|
236
260
|
<br />
|
|
237
|
-
<a href="https://
|
|
261
|
+
<a href="https://www.bamboocreative.nz">bamboocreative.nz</a>
|
|
238
262
|
</td>
|
|
239
263
|
</tr>
|
|
240
264
|
</table>
|
|
@@ -275,6 +299,16 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
275
299
|
</td>
|
|
276
300
|
</tr>
|
|
277
301
|
<tr>
|
|
302
|
+
<td align="center">
|
|
303
|
+
<a href="https://fungible.systems/">
|
|
304
|
+
<img src="https://avatars.githubusercontent.com/u/80220121?s=200&v=4" width="100px;" alt="Fungible Systems logo"/>
|
|
305
|
+
</a>
|
|
306
|
+
<br />
|
|
307
|
+
<b>Fungible Systems</b>
|
|
308
|
+
<br/>
|
|
309
|
+
<a href="https://fungible.systems/">fungible.systems</a>
|
|
310
|
+
<br />
|
|
311
|
+
</td>
|
|
278
312
|
<td align="center">
|
|
279
313
|
<a href="https://adaptable.io/">
|
|
280
314
|
<img src="https://avatars.githubusercontent.com/u/60378268?s=200&v=4" width="100px;" alt=""/>
|
|
@@ -303,46 +337,67 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
303
337
|
|
|
304
338
|
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
339
|
|
|
340
|
+
#### Resources
|
|
341
|
+
|
|
342
|
+
- [Total TypeScript Zod Tutorial](https://www.totaltypescript.com/tutorials/zod) by [@mattpocockuk](https://twitter.com/mattpocockuk)
|
|
343
|
+
- [Fixing TypeScript's Blindspot: Runtime Typechecking](https://www.youtube.com/watch?v=rY_XqfSHock) by [@jherr](https://twitter.com/jherr)
|
|
344
|
+
|
|
345
|
+
#### API libraries
|
|
346
|
+
|
|
306
347
|
- [`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
348
|
- [`@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
349
|
- [`zod-endpoints`](https://github.com/flock-community/zod-endpoints): Contract-first strictly typed endpoints with Zod. OpenAPI compatible.
|
|
350
|
+
- [`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.
|
|
351
|
+
- [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
|
|
315
352
|
- [`express-zod-api`](https://github.com/RobinTail/express-zod-api): Build Express-based APIs with I/O schema validation and custom middlewares.
|
|
353
|
+
|
|
354
|
+
#### Form integrations
|
|
355
|
+
|
|
356
|
+
- [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form.
|
|
357
|
+
- [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s
|
|
358
|
+
- [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod.
|
|
359
|
+
- [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod.
|
|
360
|
+
- [`zodix`](https://github.com/rileytomasek/zodix): Zod utilities for FormData and URLSearchParams in Remix loaders and actions.
|
|
361
|
+
|
|
362
|
+
#### Zod to X
|
|
363
|
+
|
|
364
|
+
- [`zod-to-ts`](https://github.com/sachinraja/zod-to-ts): Generate TypeScript definitions from Zod schemas.
|
|
316
365
|
- [`zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema): Convert your Zod schemas into [JSON Schemas](https://json-schema.org/).
|
|
366
|
+
- [`@anatine/zod-openapi`](https://github.com/anatine/zod-plugins/tree/main/packages/zod-openapi): Converts a Zod schema to an OpenAPI v3.x `SchemaObject`.
|
|
367
|
+
- [`zod-fast-check`](https://github.com/DavidTimms/zod-fast-check): Generate `fast-check` arbitraries from Zod schemas.
|
|
368
|
+
- [`zod-dto`](https://github.com/kbkk/abitia/tree/master/packages/zod-dto): Generate Nest.js DTOs from a Zod schema.
|
|
369
|
+
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas.
|
|
370
|
+
- [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters.
|
|
371
|
+
- [`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.
|
|
372
|
+
|
|
373
|
+
#### X to Zod
|
|
374
|
+
|
|
375
|
+
- [`ts-to-zod`](https://github.com/fabien0102/ts-to-zod): Convert TypeScript definitions into Zod schemas.
|
|
376
|
+
- [`@runtyping/zod`](https://github.com/johngeorgewright/runtyping/tree/master/packages/zod): Generate Zod from static types & JSON schema.
|
|
317
377
|
- [`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
378
|
- [`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
379
|
- [`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
380
|
- [`zod-prisma`](https://github.com/CarterGrimmeisen/zod-prisma): Generate Zod schemas from your Prisma schema.
|
|
323
|
-
- [`
|
|
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
|
|
381
|
+
- [`Supervillain`](https://github.com/Southclaws/supervillain): Generate Zod schemas from your Go structs.
|
|
326
382
|
- [`prisma-zod-generator`](https://github.com/omar-dulaimi/prisma-zod-generator): Emit Zod schemas from your Prisma schema.
|
|
327
383
|
- [`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
384
|
|
|
335
|
-
####
|
|
385
|
+
#### Mocking
|
|
336
386
|
|
|
337
|
-
- [
|
|
338
|
-
- [`zod-
|
|
339
|
-
|
|
387
|
+
- [`@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).
|
|
388
|
+
- [`zod-mocking`](https://github.com/dipasqualew/zod-mocking): Generate mock data from your Zod schemas.
|
|
389
|
+
|
|
390
|
+
#### Powered by Zod
|
|
391
|
+
|
|
392
|
+
- [`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.
|
|
393
|
+
- [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
|
|
394
|
+
- [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
|
|
340
395
|
|
|
341
396
|
## Installation
|
|
342
397
|
|
|
343
398
|
### Requirements
|
|
344
399
|
|
|
345
|
-
- TypeScript 4.
|
|
400
|
+
- TypeScript 4.5+!
|
|
346
401
|
- You must enable `strict` mode in your `tsconfig.json`. This is a best practice for all TypeScript projects.
|
|
347
402
|
|
|
348
403
|
```ts
|
|
@@ -356,17 +411,16 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
356
411
|
}
|
|
357
412
|
```
|
|
358
413
|
|
|
359
|
-
### Node/
|
|
360
|
-
|
|
361
|
-
To install Zod v3:
|
|
414
|
+
### From `npm` (Node/Bun)
|
|
362
415
|
|
|
363
416
|
```sh
|
|
364
417
|
npm install zod # npm
|
|
365
418
|
yarn add zod # yarn
|
|
419
|
+
bun add zod # bun
|
|
366
420
|
pnpm add zod # pnpm
|
|
367
421
|
```
|
|
368
422
|
|
|
369
|
-
### Deno
|
|
423
|
+
### From `deno.land/x` (Deno)
|
|
370
424
|
|
|
371
425
|
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
426
|
|
|
@@ -428,6 +482,7 @@ z.number();
|
|
|
428
482
|
z.bigint();
|
|
429
483
|
z.boolean();
|
|
430
484
|
z.date();
|
|
485
|
+
z.symbol();
|
|
431
486
|
|
|
432
487
|
// empty types
|
|
433
488
|
z.undefined();
|
|
@@ -449,8 +504,12 @@ z.never();
|
|
|
449
504
|
```ts
|
|
450
505
|
const tuna = z.literal("tuna");
|
|
451
506
|
const twelve = z.literal(12);
|
|
507
|
+
const twobig = z.literal(2n); // bigint literal
|
|
452
508
|
const tru = z.literal(true);
|
|
453
509
|
|
|
510
|
+
const terrificSymbol = Symbol("terrific");
|
|
511
|
+
const terrific = z.literal(terrificSymbol);
|
|
512
|
+
|
|
454
513
|
// retrieve literal value
|
|
455
514
|
tuna.value; // "tuna"
|
|
456
515
|
```
|
|
@@ -472,18 +531,11 @@ z.string().cuid();
|
|
|
472
531
|
z.string().regex(regex);
|
|
473
532
|
z.string().startsWith(string);
|
|
474
533
|
z.string().endsWith(string);
|
|
475
|
-
|
|
476
|
-
//
|
|
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" });
|
|
534
|
+
z.string().trim(); // trim whitespace
|
|
535
|
+
z.string().datetime(); // defaults to UTC, see below for options
|
|
484
536
|
```
|
|
485
537
|
|
|
486
|
-
> Check out [validator.js](https://github.com/validatorjs/validator.js) for a bunch of other useful string validation functions.
|
|
538
|
+
> 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
539
|
|
|
488
540
|
You can customize some common error messages when creating a string schema.
|
|
489
541
|
|
|
@@ -505,6 +557,67 @@ z.string().url({ message: "Invalid url" });
|
|
|
505
557
|
z.string().uuid({ message: "Invalid UUID" });
|
|
506
558
|
z.string().startsWith("https://", { message: "Must provide secure URL" });
|
|
507
559
|
z.string().endsWith(".com", { message: "Only .com domains allowed" });
|
|
560
|
+
z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
## Coercion for primitives
|
|
564
|
+
|
|
565
|
+
Zod now provides a more convenient way to coerce primitive values.
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
const schema = z.coerce.string();
|
|
569
|
+
schema.parse("tuna"); // => "tuna"
|
|
570
|
+
schema.parse(12); // => "12"
|
|
571
|
+
schema.parse(true); // => "true"
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
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.
|
|
575
|
+
|
|
576
|
+
```ts
|
|
577
|
+
z.coerce.string().email().min(5);
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
All primitive types support coercion.
|
|
581
|
+
|
|
582
|
+
```ts
|
|
583
|
+
z.coerce.string(); // String(input)
|
|
584
|
+
z.coerce.number(); // Number(input)
|
|
585
|
+
z.coerce.boolean(); // Boolean(input)
|
|
586
|
+
z.coerce.bigint(); // BigInt(input)
|
|
587
|
+
z.coerce.date(); // new Date(input)
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Datetime validation
|
|
591
|
+
|
|
592
|
+
The `z.string().datetime()` method defaults to UTC validation: no timezone offsets with arbitrary sub-second decimal precision.
|
|
593
|
+
|
|
594
|
+
```ts
|
|
595
|
+
const datetime = z.string().datetime();
|
|
596
|
+
|
|
597
|
+
datetime.parse("2020-01-01T00:00:00Z"); // pass
|
|
598
|
+
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
|
|
599
|
+
datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
|
|
600
|
+
datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Timezone offsets can be allowed by setting the `offset` option to `true`.
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
const datetime = z.string().datetime({ offset: true });
|
|
607
|
+
|
|
608
|
+
datetime.parse("2020-01-01T00:00:00+02:00"); // pass
|
|
609
|
+
datetime.parse("2020-01-01T00:00:00.123+02:00"); // pass (millis optional)
|
|
610
|
+
datetime.parse("2020-01-01T00:00:00Z"); // pass (Z still supported)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
You can additionally constrain the allowable `precision`. By default, arbitrary sub-second precision is supported (but optional).
|
|
614
|
+
|
|
615
|
+
```ts
|
|
616
|
+
const datetime = z.string().datetime({ precision: 3 });
|
|
617
|
+
|
|
618
|
+
datetime.parse("2020-01-01T00:00:00.123Z"); // pass
|
|
619
|
+
datetime.parse("2020-01-01T00:00:00Z"); // fail
|
|
620
|
+
datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
|
|
508
621
|
```
|
|
509
622
|
|
|
510
623
|
## Numbers
|
|
@@ -534,6 +647,8 @@ z.number().negative(); // < 0
|
|
|
534
647
|
z.number().nonpositive(); // <= 0
|
|
535
648
|
|
|
536
649
|
z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)
|
|
650
|
+
|
|
651
|
+
z.number().finite(); // value must be finite, not Infinity or -Infinity
|
|
537
652
|
```
|
|
538
653
|
|
|
539
654
|
Optionally, you can pass in a second argument to provide a custom error message.
|
|
@@ -758,7 +873,7 @@ nullableString.parse(null); // => null
|
|
|
758
873
|
Or use the `.nullable()` method.
|
|
759
874
|
|
|
760
875
|
```ts
|
|
761
|
-
const E = z.string().nullable(); // equivalent to
|
|
876
|
+
const E = z.string().nullable(); // equivalent to nullableString
|
|
762
877
|
type E = z.infer<typeof E>; // string | null
|
|
763
878
|
```
|
|
764
879
|
|
|
@@ -927,6 +1042,41 @@ const deepPartialUser = user.deepPartial();
|
|
|
927
1042
|
|
|
928
1043
|
> Important limitation: deep partials only work as expected in hierarchies of objects, arrays, and tuples.
|
|
929
1044
|
|
|
1045
|
+
### `.required`
|
|
1046
|
+
|
|
1047
|
+
Contrary to the `.partial` method, the `.required` method makes all properties required.
|
|
1048
|
+
|
|
1049
|
+
Starting from this object:
|
|
1050
|
+
|
|
1051
|
+
```ts
|
|
1052
|
+
const user = z.object({
|
|
1053
|
+
email: z.string()
|
|
1054
|
+
username: z.string(),
|
|
1055
|
+
}).partial();
|
|
1056
|
+
// { email?: string | undefined; username?: string | undefined }
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
We can create a required version:
|
|
1060
|
+
|
|
1061
|
+
```ts
|
|
1062
|
+
const requiredUser = user.required();
|
|
1063
|
+
// { email: string; username: string }
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
You can also specify which properties to make required:
|
|
1067
|
+
|
|
1068
|
+
```ts
|
|
1069
|
+
const requiredEmail = user.required({
|
|
1070
|
+
email: true,
|
|
1071
|
+
});
|
|
1072
|
+
/*
|
|
1073
|
+
{
|
|
1074
|
+
email: string;
|
|
1075
|
+
username?: string | undefined;
|
|
1076
|
+
}
|
|
1077
|
+
*/
|
|
1078
|
+
```
|
|
1079
|
+
|
|
930
1080
|
### `.passthrough`
|
|
931
1081
|
|
|
932
1082
|
By default Zod object schemas strip out unrecognized keys during parsing.
|
|
@@ -1103,21 +1253,25 @@ const stringOrNumber = z.string().or(z.number());
|
|
|
1103
1253
|
|
|
1104
1254
|
## Discriminated unions
|
|
1105
1255
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1256
|
+
A discriminated union is a union of object schemas that all share a particular key.
|
|
1257
|
+
|
|
1258
|
+
```ts
|
|
1259
|
+
type MyUnion =
|
|
1260
|
+
| { status: "success"; data: string }
|
|
1261
|
+
| { status: "failed"; error: Error };
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
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.
|
|
1108
1265
|
|
|
1109
|
-
|
|
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".
|
|
1266
|
+
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
1267
|
|
|
1114
1268
|
```ts
|
|
1115
|
-
const
|
|
1116
|
-
.
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1269
|
+
const myUnion = z.discriminatedUnion("status", [
|
|
1270
|
+
z.object({ status: z.literal("success"), data: z.string() }),
|
|
1271
|
+
z.object({ status: z.literal("failed"), error: z.instanceof(Error) }),
|
|
1272
|
+
]);
|
|
1273
|
+
|
|
1274
|
+
myUnion.parse({ type: "success", data: "yippie ki yay" });
|
|
1121
1275
|
```
|
|
1122
1276
|
|
|
1123
1277
|
## Records
|
|
@@ -1815,6 +1969,37 @@ numberWithRandomDefault.parse(undefined); // => 0.1871840107401901
|
|
|
1815
1969
|
numberWithRandomDefault.parse(undefined); // => 0.7223408162401552
|
|
1816
1970
|
```
|
|
1817
1971
|
|
|
1972
|
+
Conceptually, this is how Zod processes default values:
|
|
1973
|
+
|
|
1974
|
+
1. If the input is `undefined`, the default value is returned
|
|
1975
|
+
2. Otherwise, the data is parsed using the base schema
|
|
1976
|
+
|
|
1977
|
+
### `.catch`
|
|
1978
|
+
|
|
1979
|
+
Use `.catch()` to provide a "catch value" to be returned in the event of a parsing error.
|
|
1980
|
+
|
|
1981
|
+
```ts
|
|
1982
|
+
const numberWithCatch = z.number().catch(42);
|
|
1983
|
+
|
|
1984
|
+
numberWithCatch.parse(5); // => 5
|
|
1985
|
+
numberWithCatch.parse("tuna"); // => 42
|
|
1986
|
+
```
|
|
1987
|
+
|
|
1988
|
+
Optionally, you can pass a function into `.catch` that will be re-executed whenever a default value needs to be generated:
|
|
1989
|
+
|
|
1990
|
+
```ts
|
|
1991
|
+
const numberWithRandomCatch = z.number().catch(Math.random);
|
|
1992
|
+
|
|
1993
|
+
numberWithRandomDefault.parse("sup"); // => 0.4413456736055323
|
|
1994
|
+
numberWithRandomDefault.parse("sup"); // => 0.1871840107401901
|
|
1995
|
+
numberWithRandomDefault.parse("sup"); // => 0.7223408162401552
|
|
1996
|
+
```
|
|
1997
|
+
|
|
1998
|
+
Conceptually, this is how Zod processes "catch values":
|
|
1999
|
+
|
|
2000
|
+
1. The data is parsed using the base schema
|
|
2001
|
+
2. If the parsing fails, the "catch value" is returned
|
|
2002
|
+
|
|
1818
2003
|
### `.optional`
|
|
1819
2004
|
|
|
1820
2005
|
A convenience method that returns an optional version of a schema.
|
|
@@ -1910,7 +2095,7 @@ petCat(fido); // works fine
|
|
|
1910
2095
|
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
2096
|
|
|
1912
2097
|
```ts
|
|
1913
|
-
const Cat = z.object({ name: z.string }).brand<"Cat">();
|
|
2098
|
+
const Cat = z.object({ name: z.string() }).brand<"Cat">();
|
|
1914
2099
|
type Cat = z.infer<typeof Cat>;
|
|
1915
2100
|
|
|
1916
2101
|
const petCat = (cat: Cat) => {};
|
|
@@ -1926,7 +2111,7 @@ petCat({ name: "fido" });
|
|
|
1926
2111
|
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
2112
|
|
|
1928
2113
|
```ts
|
|
1929
|
-
const Cat = z.object({ name: z.string }).brand<"Cat">();
|
|
2114
|
+
const Cat = z.object({ name: z.string() }).brand<"Cat">();
|
|
1930
2115
|
type Cat = z.infer<typeof Cat>;
|
|
1931
2116
|
// {name: string} & {[symbol]: "Cat"}
|
|
1932
2117
|
```
|
|
@@ -2051,6 +2236,8 @@ if (!data.success) {
|
|
|
2051
2236
|
|
|
2052
2237
|
> 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
2238
|
|
|
2239
|
+
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)
|
|
2240
|
+
|
|
2054
2241
|
### Error formatting
|
|
2055
2242
|
|
|
2056
2243
|
You can use the `.format()` method to convert this error into a nested object.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare namespace env {
|
|
2
|
+
const browser: boolean;
|
|
3
|
+
const node: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const root: boolean;
|
|
6
|
+
export declare const parser: string;
|
|
7
|
+
export declare const plugins: string[];
|
|
8
|
+
declare const _extends: string[];
|
|
9
|
+
export { _extends as extends };
|
|
10
|
+
export declare const rules: {
|
|
11
|
+
"import/order": number;
|
|
12
|
+
"import/no-unresolved": number;
|
|
13
|
+
"import/no-duplicates": number;
|
|
14
|
+
/**
|
|
15
|
+
* eslint-plugin-simple-import-sort @see https://github.com/lydell/eslint-plugin-simple-import-sort
|
|
16
|
+
*/
|
|
17
|
+
"sort-imports": number;
|
|
18
|
+
"simple-import-sort/imports": number;
|
|
19
|
+
"simple-import-sort/exports": number;
|
|
20
|
+
/**
|
|
21
|
+
* @typescript-eslint/eslint-plugin @see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin
|
|
22
|
+
*/
|
|
23
|
+
"@typescript-eslint/no-namespace": string;
|
|
24
|
+
"@typescript-eslint/explicit-module-boundary-types": string;
|
|
25
|
+
"@typescript-eslint/no-explicit-any": string;
|
|
26
|
+
"@typescript-eslint/ban-types": string;
|
|
27
|
+
"@typescript-eslint/no-unused-vars": string;
|
|
28
|
+
"@typescript-eslint/no-empty-function": string;
|
|
29
|
+
"@typescript-eslint/ban-ts-comment": string;
|
|
30
|
+
"@typescript-eslint/no-non-null-assertion": string;
|
|
31
|
+
"@typescript-eslint/no-empty-interface": string;
|
|
32
|
+
/**
|
|
33
|
+
* ESLint core rules @see https://eslint.org/docs/rules/
|
|
34
|
+
*/
|
|
35
|
+
"no-case-declarations": string;
|
|
36
|
+
"no-empty": string;
|
|
37
|
+
"no-useless-escape": string;
|
|
38
|
+
"no-control-regex": string;
|
|
39
|
+
"ban/ban": (number | {
|
|
40
|
+
name: string[];
|
|
41
|
+
message: string;
|
|
42
|
+
})[];
|
|
43
|
+
};
|
package/lib/.eslintrc.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
module.exports = {
|
|
3
|
+
env: { browser: true, node: true },
|
|
4
|
+
root: true,
|
|
5
|
+
parser: "@typescript-eslint/parser",
|
|
6
|
+
plugins: [
|
|
7
|
+
"@typescript-eslint",
|
|
8
|
+
"import",
|
|
9
|
+
"simple-import-sort",
|
|
10
|
+
"unused-imports",
|
|
11
|
+
"ban",
|
|
12
|
+
],
|
|
13
|
+
extends: [
|
|
14
|
+
"eslint:recommended",
|
|
15
|
+
"plugin:@typescript-eslint/recommended",
|
|
16
|
+
"prettier",
|
|
17
|
+
],
|
|
18
|
+
rules: {
|
|
19
|
+
"import/order": 0,
|
|
20
|
+
"import/no-unresolved": 0,
|
|
21
|
+
"import/no-duplicates": 1,
|
|
22
|
+
/**
|
|
23
|
+
* eslint-plugin-simple-import-sort @see https://github.com/lydell/eslint-plugin-simple-import-sort
|
|
24
|
+
*/
|
|
25
|
+
"sort-imports": 0,
|
|
26
|
+
"simple-import-sort/imports": 1,
|
|
27
|
+
"simple-import-sort/exports": 1,
|
|
28
|
+
/**
|
|
29
|
+
* @typescript-eslint/eslint-plugin @see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin
|
|
30
|
+
*/
|
|
31
|
+
"@typescript-eslint/no-namespace": "off",
|
|
32
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
33
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
34
|
+
"@typescript-eslint/ban-types": "off",
|
|
35
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
36
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
37
|
+
"@typescript-eslint/ban-ts-comment": "off",
|
|
38
|
+
"@typescript-eslint/no-non-null-assertion": "off",
|
|
39
|
+
"@typescript-eslint/no-empty-interface": "off",
|
|
40
|
+
/**
|
|
41
|
+
* ESLint core rules @see https://eslint.org/docs/rules/
|
|
42
|
+
*/
|
|
43
|
+
"no-case-declarations": "off",
|
|
44
|
+
"no-empty": "off",
|
|
45
|
+
"no-useless-escape": "off",
|
|
46
|
+
"no-control-regex": "off",
|
|
47
|
+
"ban/ban": [
|
|
48
|
+
2,
|
|
49
|
+
{
|
|
50
|
+
name: ["Object", "keys"],
|
|
51
|
+
message: "Object.keys() is not supported in legacy browsers, use objectKeys()",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: ["Object", "setPrototypeOf"],
|
|
55
|
+
message: "Object.setPrototypeOf() is not supported in legacy browsers",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: ["Number", "isNaN"],
|
|
59
|
+
message: "Number.isNaN() is not supported in legacy browsers",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: ["Number", "isInteger"],
|
|
63
|
+
message: "Number.isInteger() is not supported in legacy browsers",
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
};
|