zod 3.21.3 → 3.21.5-alpha.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 +138 -74
- package/lib/helpers/parseUtil.js +2 -1
- package/lib/helpers/util.d.ts +1 -1
- package/lib/index.mjs +58 -22
- package/lib/index.umd.js +58 -22
- package/lib/types.d.ts +8 -6
- package/lib/types.js +36 -20
- package/package.json +12 -11
- package/lib/__tests__/Mocker.d.ts +0 -17
- package/lib/__tests__/Mocker.js +0 -57
- package/lib/benchmarks/discriminatedUnion.d.ts +0 -5
- package/lib/benchmarks/discriminatedUnion.js +0 -79
- package/lib/benchmarks/index.d.ts +0 -1
- package/lib/benchmarks/index.js +0 -46
- package/lib/benchmarks/object.d.ts +0 -5
- package/lib/benchmarks/object.js +0 -70
- package/lib/benchmarks/primitives.d.ts +0 -5
- package/lib/benchmarks/primitives.js +0 -136
- package/lib/benchmarks/realworld.d.ts +0 -5
- package/lib/benchmarks/realworld.js +0 -56
- package/lib/benchmarks/string.d.ts +0 -5
- package/lib/benchmarks/string.js +0 -55
- package/lib/benchmarks/union.d.ts +0 -5
- package/lib/benchmarks/union.js +0 -79
package/README.md
CHANGED
|
@@ -45,20 +45,32 @@
|
|
|
45
45
|
|
|
46
46
|
#### Go to [zod.js.org](https://zod.js.org) >> -->
|
|
47
47
|
|
|
48
|
+
- [Table of contents](#table-of-contents)
|
|
48
49
|
- [Introduction](#introduction)
|
|
49
50
|
- [Sponsors](#sponsors)
|
|
51
|
+
- [Gold](#gold)
|
|
52
|
+
- [Silver](#silver)
|
|
53
|
+
- [Bronze](#bronze)
|
|
50
54
|
- [Ecosystem](#ecosystem)
|
|
55
|
+
- [Resources](#resources)
|
|
56
|
+
- [API libraries](#api-libraries)
|
|
57
|
+
- [Form integrations](#form-integrations)
|
|
58
|
+
- [Zod to X](#zod-to-x)
|
|
59
|
+
- [X to Zod](#x-to-zod)
|
|
60
|
+
- [Mocking](#mocking)
|
|
61
|
+
- [Powered by Zod](#powered-by-zod)
|
|
62
|
+
- [Utilities for Zod](#utilities-for-zod)
|
|
51
63
|
- [Installation](#installation)
|
|
52
64
|
- [Requirements](#requirements)
|
|
53
|
-
- [Node/
|
|
54
|
-
- [Deno](#from-denolandx-deno)
|
|
65
|
+
- [From `npm` (Node/Bun)](#from-npm-nodebun)
|
|
66
|
+
- [From `deno.land/x` (Deno)](#from-denolandx-deno)
|
|
55
67
|
- [Basic usage](#basic-usage)
|
|
56
68
|
- [Primitives](#primitives)
|
|
57
69
|
- [Coercion for primitives](#coercion-for-primitives)
|
|
58
70
|
- [Literals](#literals)
|
|
59
71
|
- [Strings](#strings)
|
|
60
|
-
- [
|
|
61
|
-
- [IP](#ip-
|
|
72
|
+
- [ISO datetimes](#iso-datetimes)
|
|
73
|
+
- [IP addresses](#ip-addresses)
|
|
62
74
|
- [Numbers](#numbers)
|
|
63
75
|
- [BigInts](#bigints)
|
|
64
76
|
- [NaNs](#nans)
|
|
@@ -69,59 +81,74 @@
|
|
|
69
81
|
- [Optionals](#optionals)
|
|
70
82
|
- [Nullables](#nullables)
|
|
71
83
|
- [Objects](#objects)
|
|
72
|
-
- [
|
|
73
|
-
- [
|
|
74
|
-
- [
|
|
75
|
-
- [
|
|
76
|
-
- [
|
|
77
|
-
- [
|
|
78
|
-
- [
|
|
79
|
-
- [
|
|
80
|
-
- [
|
|
81
|
-
- [
|
|
82
|
-
- [
|
|
84
|
+
- [`.shape`](#shape)
|
|
85
|
+
- [`.keyof`](#keyof)
|
|
86
|
+
- [`.extend`](#extend)
|
|
87
|
+
- [`.merge`](#merge)
|
|
88
|
+
- [`.pick/.omit`](#pickomit)
|
|
89
|
+
- [`.partial`](#partial)
|
|
90
|
+
- [`.deepPartial`](#deeppartial)
|
|
91
|
+
- [`.required`](#required)
|
|
92
|
+
- [`.passthrough`](#passthrough)
|
|
93
|
+
- [`.strict`](#strict)
|
|
94
|
+
- [`.strip`](#strip)
|
|
95
|
+
- [`.catchall`](#catchall)
|
|
83
96
|
- [Arrays](#arrays)
|
|
84
|
-
- [
|
|
85
|
-
- [
|
|
86
|
-
- [
|
|
97
|
+
- [`.element`](#element)
|
|
98
|
+
- [`.nonempty`](#nonempty)
|
|
99
|
+
- [`.min/.max/.length`](#minmaxlength)
|
|
87
100
|
- [Tuples](#tuples)
|
|
88
101
|
- [Unions](#unions)
|
|
89
|
-
- [Discriminated
|
|
102
|
+
- [Discriminated unions](#discriminated-unions)
|
|
90
103
|
- [Records](#records)
|
|
104
|
+
- [Record key type](#record-key-type)
|
|
91
105
|
- [Maps](#maps)
|
|
92
106
|
- [Sets](#sets)
|
|
93
107
|
- [Intersections](#intersections)
|
|
94
108
|
- [Recursive types](#recursive-types)
|
|
109
|
+
- [ZodType with ZodEffects](#zodtype-with-zodeffects)
|
|
95
110
|
- [JSON type](#json-type)
|
|
96
|
-
- [Cyclical
|
|
111
|
+
- [Cyclical objects](#cyclical-objects)
|
|
97
112
|
- [Promises](#promises)
|
|
98
113
|
- [Instanceof](#instanceof)
|
|
99
114
|
- [Functions](#functions)
|
|
100
115
|
- [Preprocess](#preprocess)
|
|
101
|
-
- [Custom](#custom-schemas)
|
|
116
|
+
- [Custom schemas](#custom-schemas)
|
|
102
117
|
- [Schema methods](#schema-methods)
|
|
103
|
-
- [
|
|
104
|
-
- [
|
|
105
|
-
- [
|
|
106
|
-
- [
|
|
107
|
-
- [
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- [
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- [
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- [
|
|
121
|
-
- [
|
|
118
|
+
- [`.parse`](#parse)
|
|
119
|
+
- [`.parseAsync`](#parseasync)
|
|
120
|
+
- [`.safeParse`](#safeparse)
|
|
121
|
+
- [`.safeParseAsync`](#safeparseasync)
|
|
122
|
+
- [`.refine`](#refine)
|
|
123
|
+
- [Arguments](#arguments)
|
|
124
|
+
- [Customize error path](#customize-error-path)
|
|
125
|
+
- [Asynchronous refinements](#asynchronous-refinements)
|
|
126
|
+
- [Relationship to transforms](#relationship-to-transforms)
|
|
127
|
+
- [`.superRefine`](#superrefine)
|
|
128
|
+
- [Abort early](#abort-early)
|
|
129
|
+
- [Type refinements](#type-refinements)
|
|
130
|
+
- [`.transform`](#transform)
|
|
131
|
+
- [Chaining order](#chaining-order)
|
|
132
|
+
- [Validating during transform](#validating-during-transform)
|
|
133
|
+
- [Relationship to refinements](#relationship-to-refinements)
|
|
134
|
+
- [Async transforms](#async-transforms)
|
|
135
|
+
- [`.default`](#default)
|
|
136
|
+
- [`.describe`](#describe)
|
|
137
|
+
- [`.catch`](#catch)
|
|
138
|
+
- [`.optional`](#optional)
|
|
139
|
+
- [`.nullable`](#nullable)
|
|
140
|
+
- [`.nullish`](#nullish)
|
|
141
|
+
- [`.array`](#array)
|
|
142
|
+
- [`.promise`](#promise)
|
|
143
|
+
- [`.or`](#or)
|
|
144
|
+
- [`.and`](#and)
|
|
145
|
+
- [`.brand`](#brand)
|
|
146
|
+
- [`.pipe()`](#pipe)
|
|
147
|
+
- [You can use `.pipe()` to fix common issues with `z.coerce`.](#you-can-use-pipe-to-fix-common-issues-with-zcoerce)
|
|
122
148
|
- [Guides and concepts](#guides-and-concepts)
|
|
123
149
|
- [Type inference](#type-inference)
|
|
124
150
|
- [Writing generic functions](#writing-generic-functions)
|
|
151
|
+
- [Constraining allowable inputs](#constraining-allowable-inputs)
|
|
125
152
|
- [Error handling](#error-handling)
|
|
126
153
|
- [Error formatting](#error-formatting)
|
|
127
154
|
- [Comparison](#comparison)
|
|
@@ -129,10 +156,9 @@
|
|
|
129
156
|
- [Yup](#yup)
|
|
130
157
|
- [io-ts](#io-ts)
|
|
131
158
|
- [Runtypes](#runtypes)
|
|
159
|
+
- [Ow](#ow)
|
|
132
160
|
- [Changelog](#changelog)
|
|
133
161
|
|
|
134
|
-
<!-- **Zod 2 is coming! Follow [@colinhacks](https://twitter.com/colinhacks) to stay updated and discuss the future of Zod.** -->
|
|
135
|
-
|
|
136
162
|
## Introduction
|
|
137
163
|
|
|
138
164
|
Zod is a TypeScript-first schema declaration and validation library. I'm using the term "schema" to broadly refer to any data type, from a simple `string` to a complex nested object.
|
|
@@ -206,7 +232,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
206
232
|
<a href="https://proxy.com">proxy.com</a>
|
|
207
233
|
</td>
|
|
208
234
|
</tr>
|
|
209
|
-
|
|
235
|
+
<tr>
|
|
210
236
|
<td align="center">
|
|
211
237
|
<a href="https://trigger.dev/">
|
|
212
238
|
<img src="https://avatars.githubusercontent.com/u/95297378?s=200&v=4" width="200px;" alt="Trigger.dev logo" />
|
|
@@ -215,16 +241,33 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
215
241
|
<b>Trigger.dev</b>
|
|
216
242
|
<br />
|
|
217
243
|
<a href="https://trigger.dev">trigger.dev</a>
|
|
244
|
+
<br/>
|
|
245
|
+
<p>Effortless automation for developers.</p>
|
|
218
246
|
</td>
|
|
219
|
-
|
|
220
|
-
<a href="https://
|
|
221
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
247
|
+
<td align="center">
|
|
248
|
+
<a href="https://transloadit.com/">
|
|
249
|
+
<img src="https://avatars.githubusercontent.com/u/125754?s=200&v=4" width="200px;" alt="Transloadit logo" />
|
|
222
250
|
</a>
|
|
223
251
|
<br />
|
|
224
|
-
<b>
|
|
252
|
+
<b>Transloadit</b>
|
|
225
253
|
<br />
|
|
226
|
-
<a href="https://
|
|
227
|
-
|
|
254
|
+
<a href="https://transloadit.com">transloadit.com</a>
|
|
255
|
+
<br/>
|
|
256
|
+
<p>Simple file processing for developers.</p>
|
|
257
|
+
</td>
|
|
258
|
+
</tr>
|
|
259
|
+
<tr>
|
|
260
|
+
<td align="center">
|
|
261
|
+
<a href="https://infisical.com">
|
|
262
|
+
<img src="https://avatars.githubusercontent.com/u/107880645?s=200&v=4" width="200px;" alt="Infisical logo" />
|
|
263
|
+
</a>
|
|
264
|
+
<br />
|
|
265
|
+
<b>Infisical</b>
|
|
266
|
+
<br />
|
|
267
|
+
<a href="https://infisical.com">infisical.com</a>
|
|
268
|
+
<br/>
|
|
269
|
+
<p>Open-source platform for secret<br/>management: sync secrets across your<br/>team/infrastructure and prevent secret leaks.</p>
|
|
270
|
+
</td>
|
|
228
271
|
</tr>
|
|
229
272
|
</table>
|
|
230
273
|
|
|
@@ -362,7 +405,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
362
405
|
</td>
|
|
363
406
|
</tr>
|
|
364
407
|
<tr>
|
|
365
|
-
|
|
408
|
+
<td align="center">
|
|
366
409
|
<a href="https://learnwithjason.dev">
|
|
367
410
|
<img src="https://avatars.githubusercontent.com/u/66575486?s=200&v=4" width="100px;" alt="Learn with Jason logo"/>
|
|
368
411
|
</a>
|
|
@@ -382,17 +425,16 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
|
|
|
382
425
|
<a href="https://ill.inc/">ill.inc</a>
|
|
383
426
|
<br />
|
|
384
427
|
</td>
|
|
385
|
-
|
|
386
|
-
<a href="https://www.
|
|
387
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
428
|
+
<td align="center">
|
|
429
|
+
<a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">
|
|
430
|
+
<img src="https://avatars.githubusercontent.com/u/48984031?s=200&v=4" width="100px;" alt="MasterBorn logo"/>
|
|
388
431
|
</a>
|
|
389
432
|
<br />
|
|
390
|
-
<b>
|
|
433
|
+
<b>MasterBorn</b>
|
|
391
434
|
<br/>
|
|
392
|
-
<a href="https://www.
|
|
393
|
-
<span>Solana non-custodial wallet</span>
|
|
435
|
+
<a href="https://www.masterborn.com/career?utm_source=github&utm_medium=referral&utm_campaign=zodsponsoring">masterborn.com</a>
|
|
394
436
|
<br />
|
|
395
|
-
</td>
|
|
437
|
+
</td>
|
|
396
438
|
</tr>
|
|
397
439
|
</table>
|
|
398
440
|
|
|
@@ -413,6 +455,8 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
413
455
|
- [`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.
|
|
414
456
|
- [`@zodios/core`](https://github.com/ecyrbe/zodios): A typescript API client with runtime and compile time validation backed by axios and zod.
|
|
415
457
|
- [`express-zod-api`](https://github.com/RobinTail/express-zod-api): Build Express-based APIs with I/O schema validation and custom middlewares.
|
|
458
|
+
- [`tapiduck`](https://github.com/sumukhbarve/monoduck/blob/main/src/tapiduck/README.md): End-to-end typesafe JSON APIs with Zod and Express; a bit like tRPC, but simpler.
|
|
459
|
+
- [`koa-zod-router`](https://github.com/JakeFenley/koa-zod-router): Create typesafe routes in Koa with I/O validation using Zod.
|
|
416
460
|
|
|
417
461
|
#### Form integrations
|
|
418
462
|
|
|
@@ -426,6 +470,8 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
426
470
|
- [`zod-i18n-map`](https://github.com/aiji42/zod-i18n): Useful for translating Zod error messages.
|
|
427
471
|
- [`@modular-forms/solid`](https://github.com/fabian-hiller/modular-forms): Modular form library for SolidJS that supports Zod for validation.
|
|
428
472
|
- [`houseform`](https://github.com/crutchcorn/houseform/): A React form library that uses Zod for validation.
|
|
473
|
+
- [`sveltekit-superforms`](https://github.com/ciscoheat/sveltekit-superforms): Supercharged form library for SvelteKit with Zod validation.
|
|
474
|
+
- [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod
|
|
429
475
|
|
|
430
476
|
#### Zod to X
|
|
431
477
|
|
|
@@ -437,6 +483,7 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
437
483
|
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas.
|
|
438
484
|
- [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters.
|
|
439
485
|
- [`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.
|
|
486
|
+
- [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod Schemas.
|
|
440
487
|
|
|
441
488
|
#### X to Zod
|
|
442
489
|
|
|
@@ -455,9 +502,13 @@ There are a growing number of tools that are built atop or support Zod natively!
|
|
|
455
502
|
|
|
456
503
|
- [`@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/faker-js/faker).
|
|
457
504
|
- [`zod-mocking`](https://github.com/dipasqualew/zod-mocking): Generate mock data from your Zod schemas.
|
|
505
|
+
- [`zod-fixture`](https://github.com/timdeschryver/zod-fixture): Use your zod schemas to automate the generation of non-relevant test fixtures in a deterministic way.
|
|
506
|
+
- [`zocker`](https://zocker.sigrist.dev): Generate plausible mock-data from your schemas.
|
|
507
|
+
- [`zodock`](https://github.com/ItMaga/zodock) Generate mock data based on Zod schemas.
|
|
458
508
|
|
|
459
509
|
#### Powered by Zod
|
|
460
510
|
|
|
511
|
+
- [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer.
|
|
461
512
|
- [`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.
|
|
462
513
|
- [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod.
|
|
463
514
|
- [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas.
|
|
@@ -494,6 +545,15 @@ bun add zod # bun
|
|
|
494
545
|
pnpm add zod # pnpm
|
|
495
546
|
```
|
|
496
547
|
|
|
548
|
+
Zod also publishes a canary version on every commit. To install the canary:
|
|
549
|
+
|
|
550
|
+
```sh
|
|
551
|
+
npm install zod@canary # npm
|
|
552
|
+
yarn add zod@canary # yarn
|
|
553
|
+
bun add zod@canary # bun
|
|
554
|
+
pnpm add zod@canary # pnpm
|
|
555
|
+
```
|
|
556
|
+
|
|
497
557
|
### From `deno.land/x` (Deno)
|
|
498
558
|
|
|
499
559
|
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:
|
|
@@ -618,7 +678,7 @@ z.coerce.boolean().parse(null); // => false
|
|
|
618
678
|
|
|
619
679
|
## Literals
|
|
620
680
|
|
|
621
|
-
Literal schemas represent a [literal type](https://www.typescriptlang.org/docs/handbook/
|
|
681
|
+
Literal schemas represent a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types), like `"hello world"` or `5`.
|
|
622
682
|
|
|
623
683
|
```ts
|
|
624
684
|
const tuna = z.literal("tuna");
|
|
@@ -966,7 +1026,7 @@ FruitEnum.parse("Cantaloupe"); // fails
|
|
|
966
1026
|
|
|
967
1027
|
**Const enums**
|
|
968
1028
|
|
|
969
|
-
The `.nativeEnum()` function works for `as const` objects as well. ⚠️ `as const`
|
|
1029
|
+
The `.nativeEnum()` function works for `as const` objects as well. ⚠️ `as const` requires TypeScript 3.4+!
|
|
970
1030
|
|
|
971
1031
|
```ts
|
|
972
1032
|
const Fruits = {
|
|
@@ -1137,7 +1197,7 @@ type NoIDRecipe = z.infer<typeof NoIDRecipe>;
|
|
|
1137
1197
|
|
|
1138
1198
|
### `.partial`
|
|
1139
1199
|
|
|
1140
|
-
Inspired by the built-in TypeScript utility type [Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#
|
|
1200
|
+
Inspired by the built-in TypeScript utility type [Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype), the `.partial` method makes all properties optional.
|
|
1141
1201
|
|
|
1142
1202
|
Starting from this object:
|
|
1143
1203
|
|
|
@@ -2399,51 +2459,55 @@ The `.pipe()` method returns a `ZodPipeline` instance.
|
|
|
2399
2459
|
You can constrain the input to types that work well with your chosen coercion. Then use `.pipe()` to apply the coercion.
|
|
2400
2460
|
|
|
2401
2461
|
without constrained input:
|
|
2462
|
+
|
|
2402
2463
|
```ts
|
|
2403
|
-
const toDate = z.coerce.date()
|
|
2464
|
+
const toDate = z.coerce.date();
|
|
2404
2465
|
|
|
2405
2466
|
// works intuitively
|
|
2406
|
-
console.log(toDate.safeParse(
|
|
2467
|
+
console.log(toDate.safeParse("2023-01-01").success); // true
|
|
2407
2468
|
|
|
2408
2469
|
// might not be what you want
|
|
2409
|
-
console.log(toDate.safeParse(null).success) // true
|
|
2470
|
+
console.log(toDate.safeParse(null).success); // true
|
|
2410
2471
|
```
|
|
2411
2472
|
|
|
2412
2473
|
with constrained input:
|
|
2474
|
+
|
|
2413
2475
|
```ts
|
|
2414
|
-
const datelike = z.union([z.number(), z.string(), z.date()])
|
|
2415
|
-
const datelikeToDate = datelike.pipe(z.coerce.date())
|
|
2476
|
+
const datelike = z.union([z.number(), z.string(), z.date()]);
|
|
2477
|
+
const datelikeToDate = datelike.pipe(z.coerce.date());
|
|
2416
2478
|
|
|
2417
2479
|
// still works intuitively
|
|
2418
|
-
console.log(datelikeToDate.safeParse(
|
|
2480
|
+
console.log(datelikeToDate.safeParse("2023-01-01").success); // true
|
|
2419
2481
|
|
|
2420
2482
|
// more likely what you want
|
|
2421
|
-
console.log(datelikeToDate.safeParse(null).success) // false
|
|
2483
|
+
console.log(datelikeToDate.safeParse(null).success); // false
|
|
2422
2484
|
```
|
|
2423
2485
|
|
|
2424
2486
|
You can also use this technique to avoid coercions that throw uncaught errors.
|
|
2425
2487
|
|
|
2426
2488
|
without constrained input:
|
|
2489
|
+
|
|
2427
2490
|
```ts
|
|
2428
|
-
const toBigInt = z.coerce.bigint()
|
|
2491
|
+
const toBigInt = z.coerce.bigint();
|
|
2429
2492
|
|
|
2430
2493
|
// works intuitively
|
|
2431
|
-
console.log(
|
|
2494
|
+
console.log(toBigInt.safeParse("42")); // true
|
|
2432
2495
|
|
|
2433
2496
|
// probably not what you want
|
|
2434
|
-
console.log(
|
|
2497
|
+
console.log(toBigInt.safeParse(null)); // throws uncaught error
|
|
2435
2498
|
```
|
|
2436
2499
|
|
|
2437
2500
|
with constrained input:
|
|
2501
|
+
|
|
2438
2502
|
```ts
|
|
2439
|
-
const toNumber = z.number().or(
|
|
2440
|
-
const toBigInt = z.bigint().or(
|
|
2503
|
+
const toNumber = z.number().or(z.string()).pipe(z.coerce.number());
|
|
2504
|
+
const toBigInt = z.bigint().or(toNumber).pipe(z.coerce.bigint());
|
|
2441
2505
|
|
|
2442
2506
|
// still works intuitively
|
|
2443
|
-
console.log(
|
|
2507
|
+
console.log(toBigInt.safeParse("42").success); // true
|
|
2444
2508
|
|
|
2445
2509
|
// error handled by zod, more likely what you want
|
|
2446
|
-
console.log(
|
|
2510
|
+
console.log(toBigInt.safeParse(null).success); // false
|
|
2447
2511
|
```
|
|
2448
2512
|
|
|
2449
2513
|
## Guides and concepts
|
package/lib/helpers/parseUtil.js
CHANGED
|
@@ -89,7 +89,8 @@ class ParseStatus {
|
|
|
89
89
|
status.dirty();
|
|
90
90
|
if (value.status === "dirty")
|
|
91
91
|
status.dirty();
|
|
92
|
-
if (
|
|
92
|
+
if (key.value !== "__proto__" &&
|
|
93
|
+
(typeof value.value !== "undefined" || pair.alwaysSet)) {
|
|
93
94
|
finalObject[key.value] = value.value;
|
|
94
95
|
}
|
|
95
96
|
}
|
package/lib/helpers/util.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare namespace objectUtil {
|
|
|
27
27
|
type requiredKeys<T extends object> = {
|
|
28
28
|
[k in keyof T]: undefined extends T[k] ? never : k;
|
|
29
29
|
}[keyof T];
|
|
30
|
-
export type addQuestionMarks<T extends object, R extends keyof T = requiredKeys<T>> = Pick<T
|
|
30
|
+
export type addQuestionMarks<T extends object, R extends keyof T = requiredKeys<T>> = Pick<Required<T>, R> & Partial<T>;
|
|
31
31
|
export type identity<T> = T;
|
|
32
32
|
export type flatten<T> = identity<{
|
|
33
33
|
[k in keyof T]: T[k];
|
package/lib/index.mjs
CHANGED
|
@@ -478,7 +478,8 @@ class ParseStatus {
|
|
|
478
478
|
status.dirty();
|
|
479
479
|
if (value.status === "dirty")
|
|
480
480
|
status.dirty();
|
|
481
|
-
if (
|
|
481
|
+
if (key.value !== "__proto__" &&
|
|
482
|
+
(typeof value.value !== "undefined" || pair.alwaysSet)) {
|
|
482
483
|
finalObject[key.value] = value.value;
|
|
483
484
|
}
|
|
484
485
|
}
|
|
@@ -812,14 +813,24 @@ class ZodType {
|
|
|
812
813
|
const cuidRegex = /^c[^\s-]{8,}$/i;
|
|
813
814
|
const cuid2Regex = /^[a-z][a-z0-9]*$/;
|
|
814
815
|
const ulidRegex = /[0-9A-HJKMNP-TV-Z]{26}/;
|
|
815
|
-
const uuidRegex =
|
|
816
|
+
// const uuidRegex =
|
|
817
|
+
// /^([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[a-f0-9]{4}-[a-f0-9]{12}|00000000-0000-0000-0000-000000000000)$/i;
|
|
818
|
+
const uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i;
|
|
816
819
|
// from https://stackoverflow.com/a/46181/1550155
|
|
817
820
|
// old version: too slow, didn't support unicode
|
|
818
821
|
// const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
|
|
819
822
|
//old email regex
|
|
820
823
|
// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i;
|
|
821
824
|
// eslint-disable-next-line
|
|
822
|
-
const emailRegex =
|
|
825
|
+
// const emailRegex =
|
|
826
|
+
// /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\])|(\[IPv6:(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))\])|([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])*(\.[A-Za-z]{2,})+))$/;
|
|
827
|
+
// const emailRegex =
|
|
828
|
+
// /^[a-zA-Z0-9\.\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\|\}\~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
829
|
+
// const emailRegex =
|
|
830
|
+
// /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
|
|
831
|
+
const emailRegex = /^([A-Z0-9_+-]+\.?)*[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;
|
|
832
|
+
// const emailRegex =
|
|
833
|
+
// /^[a-z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9-]+(?:\.[a-z0-9\-]+)*$/i;
|
|
823
834
|
// from https://thekevinscott.com/emojis-in-javascript/#writing-a-regular-expression
|
|
824
835
|
const emojiRegex = /^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u;
|
|
825
836
|
const ipv4Regex = /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/;
|
|
@@ -2930,6 +2941,12 @@ class ZodRecord extends ZodType {
|
|
|
2930
2941
|
}
|
|
2931
2942
|
}
|
|
2932
2943
|
class ZodMap extends ZodType {
|
|
2944
|
+
get keySchema() {
|
|
2945
|
+
return this._def.keyType;
|
|
2946
|
+
}
|
|
2947
|
+
get valueSchema() {
|
|
2948
|
+
return this._def.valueType;
|
|
2949
|
+
}
|
|
2933
2950
|
_parse(input) {
|
|
2934
2951
|
const { status, ctx } = this._processInputParams(input);
|
|
2935
2952
|
if (ctx.parsedType !== ZodParsedType.map) {
|
|
@@ -3239,7 +3256,7 @@ ZodLiteral.create = (value, params) => {
|
|
|
3239
3256
|
};
|
|
3240
3257
|
function createZodEnum(values, params) {
|
|
3241
3258
|
return new ZodEnum({
|
|
3242
|
-
values
|
|
3259
|
+
values,
|
|
3243
3260
|
typeName: ZodFirstPartyTypeKind.ZodEnum,
|
|
3244
3261
|
...processCreateParams(params),
|
|
3245
3262
|
});
|
|
@@ -3381,8 +3398,29 @@ class ZodEffects extends ZodType {
|
|
|
3381
3398
|
_parse(input) {
|
|
3382
3399
|
const { status, ctx } = this._processInputParams(input);
|
|
3383
3400
|
const effect = this._def.effect || null;
|
|
3401
|
+
const checkCtx = {
|
|
3402
|
+
addIssue: (arg) => {
|
|
3403
|
+
addIssueToContext(ctx, arg);
|
|
3404
|
+
if (arg.fatal) {
|
|
3405
|
+
status.abort();
|
|
3406
|
+
}
|
|
3407
|
+
else {
|
|
3408
|
+
status.dirty();
|
|
3409
|
+
}
|
|
3410
|
+
},
|
|
3411
|
+
get path() {
|
|
3412
|
+
return ctx.path;
|
|
3413
|
+
},
|
|
3414
|
+
};
|
|
3415
|
+
checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx);
|
|
3384
3416
|
if (effect.type === "preprocess") {
|
|
3385
|
-
const processed = effect.transform(ctx.data);
|
|
3417
|
+
const processed = effect.transform(ctx.data, checkCtx);
|
|
3418
|
+
if (ctx.common.issues.length) {
|
|
3419
|
+
return {
|
|
3420
|
+
status: "dirty",
|
|
3421
|
+
value: ctx.data,
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3386
3424
|
if (ctx.common.async) {
|
|
3387
3425
|
return Promise.resolve(processed).then((processed) => {
|
|
3388
3426
|
return this._def.schema._parseAsync({
|
|
@@ -3400,21 +3438,6 @@ class ZodEffects extends ZodType {
|
|
|
3400
3438
|
});
|
|
3401
3439
|
}
|
|
3402
3440
|
}
|
|
3403
|
-
const checkCtx = {
|
|
3404
|
-
addIssue: (arg) => {
|
|
3405
|
-
addIssueToContext(ctx, arg);
|
|
3406
|
-
if (arg.fatal) {
|
|
3407
|
-
status.abort();
|
|
3408
|
-
}
|
|
3409
|
-
else {
|
|
3410
|
-
status.dirty();
|
|
3411
|
-
}
|
|
3412
|
-
},
|
|
3413
|
-
get path() {
|
|
3414
|
-
return ctx.path;
|
|
3415
|
-
},
|
|
3416
|
-
};
|
|
3417
|
-
checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx);
|
|
3418
3441
|
if (effect.type === "refinement") {
|
|
3419
3442
|
const executeRefinement = (acc
|
|
3420
3443
|
// effect: RefinementEffect<any>
|
|
@@ -3719,13 +3742,26 @@ class ZodPipeline extends ZodType {
|
|
|
3719
3742
|
}
|
|
3720
3743
|
}
|
|
3721
3744
|
const custom = (check, params = {},
|
|
3722
|
-
/*
|
|
3745
|
+
/*
|
|
3746
|
+
* @deprecated
|
|
3747
|
+
*
|
|
3748
|
+
* Pass `fatal` into the params object instead:
|
|
3749
|
+
*
|
|
3750
|
+
* ```ts
|
|
3751
|
+
* z.string().custom((val) => val.length > 5, { fatal: false })
|
|
3752
|
+
* ```
|
|
3753
|
+
*
|
|
3754
|
+
*/
|
|
3723
3755
|
fatal) => {
|
|
3724
3756
|
if (check)
|
|
3725
3757
|
return ZodAny.create().superRefine((data, ctx) => {
|
|
3726
3758
|
var _a, _b;
|
|
3727
3759
|
if (!check(data)) {
|
|
3728
|
-
const p = typeof params === "function"
|
|
3760
|
+
const p = typeof params === "function"
|
|
3761
|
+
? params(data)
|
|
3762
|
+
: typeof params === "string"
|
|
3763
|
+
? { message: params }
|
|
3764
|
+
: params;
|
|
3729
3765
|
const _fatal = (_b = (_a = p.fatal) !== null && _a !== void 0 ? _a : fatal) !== null && _b !== void 0 ? _b : true;
|
|
3730
3766
|
const p2 = typeof p === "string" ? { message: p } : p;
|
|
3731
3767
|
ctx.addIssue({ code: "custom", ...p2, fatal: _fatal });
|