zod 3.24.2 → 3.24.4

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
@@ -1,13 +1,12 @@
1
1
  <p align="center">
2
- <img src="logo.svg" width="200px" align="center" alt="Zod logo" />
2
+ <img src="https://raw.githubusercontent.com/colinhacks/zod/main/logo.svg" width="200px" align="center" alt="Zod logo" />
3
3
  <h1 align="center">Zod</h1>
4
4
  <p align="center">
5
- <a href="https://zod.dev">https://zod.dev</a>
6
- <br/>
5
+ <a href="https://zod.dev">zod.dev</a>
6
+ <br/>
7
7
  TypeScript-first schema validation with static type inference
8
8
  </p>
9
9
  </p>
10
- <br/>
11
10
  <p align="center">
12
11
  <a href="https://github.com/colinhacks/zod/actions?query=branch%3Amain"><img src="https://github.com/colinhacks/zod/actions/workflows/test.yml/badge.svg?event=push&branch=main" alt="Zod CI status" /></a>
13
12
  <a href="https://twitter.com/colinhacks" rel="nofollow"><img src="https://img.shields.io/badge/created%20by-@colinhacks-4BBAAB.svg" alt="Created by Colin McDonnell"></a>
@@ -17,29 +16,42 @@
17
16
  </p>
18
17
 
19
18
  <div align="center">
20
- <a href="https://zod.dev">Documentation</a>
19
+ <a href="https://zod.dev">Website</a>
21
20
  <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
22
21
  <a href="https://discord.gg/RcG33DQJdf">Discord</a>
23
22
  <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
24
- <a href="https://www.npmjs.com/package/zod">npm</a>
25
- <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
26
- <a href="https://deno.land/x/zod">deno</a>
27
- <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
28
- <a href="https://github.com/colinhacks/zod/issues/new">Issues</a>
23
+ <a href="https://twitter.com/colinhacks">𝕏</a>
29
24
  <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
30
- <a href="https://twitter.com/colinhacks">@colinhacks</a>
31
- <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
32
- <a href="https://trpc.io">tRPC</a>
25
+ <a href="https://bsky.app/profile/zod.dev">Bluesky</a>
33
26
  <br />
34
27
  </div>
35
28
 
29
+ <br/><br/>
30
+
31
+ <table align="center" style="justify-content:center;align-items:center;display:flex;"><td>
32
+ <p align="center">Zod 4 is now in beta!
33
+ <br/>
34
+ <a target="_blank" rel="noopener noreferrer" href="https://v4.zod.dev/v4">Read the announcement 👉</a></p></td>
35
+ </table>
36
+
36
37
  <br/>
37
38
  <br/>
38
39
 
39
- <!-- <p><strong>Announcement ✨</strong> Zod has recieved the <a href="https://go.clerk.com/zod-clerk">Clerk</a> OSS Fellowship!<br/>Read the announcement post 👉 <a href="https://go.clerk.com/zod-clerk">clerk.com/blog/zod-fellowship</a></p> -->
40
+ <h2 align="center">Featured sponsor: Stainless</h2>
40
41
 
41
- [![clerk announcement](https://github.com/colinhacks/zod/assets/3084745/6327cf99-8d82-4b44-a5b1-ba2b5c2ff6ad)](https://go.clerk.com/hqN4rp7)
42
+ <div align="center">
43
+ <a href="https://www.stainless.com/?utm_source=zod">
44
+ <picture width="95%" >
45
+ <source media="(prefers-color-scheme: dark)" srcset="https://i.imgur.com/bjyoaHY.jpeg">
46
+ <img alt="stainless logo" src="https://i.imgur.com/bjyoaHY.jpeg" width="95%">
47
+ </picture>
48
+ </a>
49
+ <br/>
50
+ <p><sub>Learn more about <a target="_blank" rel="noopener noreferrer" href="mailto:sponsorship@colinhacks.com">featured sponsorships</a></sub></p>
51
+ </div>
42
52
 
53
+ <!-- <hr/> -->
54
+ <br/>
43
55
  <br/>
44
56
 
45
57
  ## Table of contents
@@ -165,6 +177,8 @@
165
177
  - [Ow](#ow)
166
178
  - [Changelog](#changelog)
167
179
 
180
+ <br/>
181
+
168
182
  ## Introduction
169
183
 
170
184
  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.
@@ -181,32 +195,12 @@ Some other great aspects:
181
195
  - Functional approach: [parse, don't validate](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/)
182
196
  - Works with plain JavaScript too! You don't need to use TypeScript.
183
197
 
184
- ## Sponsors
185
-
186
- Sponsorship at any level is appreciated and encouraged. If you built a paid product using Zod, consider one of the [corporate tiers](https://github.com/sponsors/colinhacks).
187
-
188
198
  <br/>
189
- <h3 align="center">Diamond</h3>
190
199
 
191
- <br/>
200
+ ## Sponsors
192
201
 
193
- <div align="center">
194
- <a href="https://go.clerk.com/PKHrcwh">
195
- <picture width="100%">
196
- <source media="(prefers-color-scheme: dark)" srcset="https://github.com/colinhacks/zod/assets/3084745/15c8c8be-189d-44ed-b3db-59bf2a21cbe3">
197
- <img alt="clerk logo" src="https://github.com/colinhacks/zod/assets/3084745/15c8c8be-189d-44ed-b3db-59bf2a21cbe3">
198
- </picture>
199
- </a>
200
- <br/>
201
- <br/>
202
- <p>
203
- The most comprehensive User Management Platform
204
- <br/>
205
- <a style="text-decoration:none;" href="https://go.clerk.com/PKHrcwh" target="_blank">clerk.com</a>
206
- </p>
207
- </div>
202
+ Sponsorship at any level is appreciated and encouraged. If you built a paid product using Zod, consider one of the [corporate tiers](https://github.com/sponsors/colinhacks).
208
203
 
209
- <br/>
210
204
  <br/>
211
205
 
212
206
  <h3 align="center">Platinum</h3>
@@ -222,7 +216,7 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
222
216
  <img alt="CodeRabbit logo" height="80px" src="https://github.com/user-attachments/assets/d791bc7d-dc60-4d55-9c31-97779839cb74">
223
217
  </picture>
224
218
  </a>
225
- <br />
219
+ <br />
226
220
  Cut code review time & bugs in half
227
221
  <br/>
228
222
  <a href="https://www.coderabbit.ai/" style="text-decoration:none;">coderabbit.ai</a>
@@ -247,7 +241,7 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
247
241
  <img alt="Courier logo" height="62px" src="https://github.com/user-attachments/assets/6b09506a-78de-47e8-a8c1-792efe31910a">
248
242
  </picture>
249
243
  </a>
250
- <br />
244
+ <br />
251
245
  The API platform for sending notifications
252
246
  <br/>
253
247
  <a href="https://www.courier.com/?utm_source=zod&utm_campaign=osssponsors" style="text-decoration:none;">courier.com</a>
@@ -263,7 +257,7 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
263
257
  <img alt="LibLab" height="62px" src="https://github.com/user-attachments/assets/3de0b617-5137-49c4-b72d-a033cbe602d8">
264
258
  </picture>
265
259
  </a>
266
- <br />
260
+ <br />
267
261
  Generate better SDKs for your APIs
268
262
  <br/>
269
263
  <a href="https://liblab.com/?utm_source=zod" style="text-decoration:none;">liblab.com</a>
@@ -281,7 +275,7 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
281
275
  <img alt="Neon" height="68px" src="https://github.com/user-attachments/assets/b5799fc8-81ff-4053-a1c3-b29adf85e7a1">
282
276
  </picture>
283
277
  </a>
284
- <br />
278
+ <br />
285
279
  Serverless Postgres — Ship faster
286
280
  <br/>
287
281
  <a href="https://neon.tech" style="text-decoration:none;">neon.tech</a>
@@ -294,10 +288,10 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
294
288
  <a href="https://retool.com/?utm_source=github&utm_medium=referral&utm_campaign=zod">
295
289
  <picture height="45px">
296
290
  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/colinhacks/zod/assets/3084745/ac65013f-aeb4-48dd-a2ee-41040b69cbe6">
297
- <img alt="stainless" height="45px" src="https://github.com/colinhacks/zod/assets/3084745/5ef4c11b-efeb-4495-90a8-41b83f798600">
291
+ <img alt="Retool" height="45px" src="https://github.com/colinhacks/zod/assets/3084745/5ef4c11b-efeb-4495-90a8-41b83f798600">
298
292
  </picture>
299
293
  </a>
300
- <br />
294
+ <br />
301
295
  Build AI apps and workflows with <a href="https://retool.com/products/ai?utm_source=github&utm_medium=referral&utm_campaign=zod">Retool AI</a>
302
296
  <br/>
303
297
  <a href="https://retool.com/?utm_source=github&utm_medium=referral&utm_campaign=zod" style="text-decoration:none;">retool.com</a>
@@ -309,16 +303,16 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
309
303
  <td align="center">
310
304
  <p></p>
311
305
  <p>
312
- <a href="https://stainlessapi.com">
306
+ <a href="https://stainless.com">
313
307
  <picture height="45px">
314
308
  <source media="(prefers-color-scheme: dark)" srcset="https://github.com/colinhacks/zod/assets/3084745/f20759c1-3e51-49d0-a31e-bbc43abec665">
315
309
  <img alt="stainless" height="45px" src="https://github.com/colinhacks/zod/assets/3084745/e9444e44-d991-4bba-a697-dbcfad608e47">
316
310
  </picture>
317
311
  </a>
318
- <br />
312
+ <br />
319
313
  Generate best-in-class SDKs
320
314
  <br/>
321
- <a href="https://stainlessapi.com" style="text-decoration:none;">stainlessapi.com</a>
315
+ <a href="https://stainless.com" style="text-decoration:none;">stainless.com</a>
322
316
  </p>
323
317
  <p></p>
324
318
  </td>
@@ -331,7 +325,7 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
331
325
  <img alt="speakeasy" height="40px" src="https://github.com/colinhacks/zod/assets/3084745/647524a4-22bb-4199-be70-404207a5a2b5">
332
326
  </picture>
333
327
  </a>
334
- <br />
328
+ <br />
335
329
  SDKs & Terraform providers for your API
336
330
  <br/>
337
331
  <a href="https://speakeasy.com/?utm_source=zod+docs" style="text-decoration:none;">speakeasy.com</a>
@@ -416,6 +410,11 @@ Sponsorship at any level is appreciated and encouraged. If you built a paid prod
416
410
  <br />
417
411
  <a style="text-decoration:none;" href="https://mux.link/zod" target="_blank">Mux</a>
418
412
  </td>
413
+ <td align="center">
414
+ <img src="https://avatars.githubusercontent.com/u/76428554?s=200&v=4" height="50px;" alt="Cybozu logo" />
415
+ <br />
416
+ <a style="text-decoration:none;" href="https://cybozu.co.jp/index.html" target="_blank">Cybozu</a>
417
+ </td>
419
418
  </tr>
420
419
  </table>
421
420
 
@@ -536,10 +535,13 @@ There are a growing number of tools that are built atop or support Zod natively!
536
535
  - [`koa-zod-router`](https://github.com/JakeFenley/koa-zod-router): Create typesafe routes in Koa with I/O validation using Zod.
537
536
  - [`zod-sockets`](https://github.com/RobinTail/zod-sockets): Zod-powered Socket.IO microframework with I/O validation and built-in AsyncAPI specs
538
537
  - [`oas-tszod-gen`](https://github.com/inkognitro/oas-tszod-gen): Client SDK code generator to convert OpenApi v3 specifications into TS endpoint caller functions with Zod types.
538
+ - [`GQLoom`](https://github.com/modevol-com/gqloom): Weave GraphQL schema and resolvers using Zod.
539
+ - [`oRPC`](https://github.com/unnoq/orpc): Typesafe APIs Made Simple
539
540
 
540
541
  #### Form integrations
541
542
 
542
543
  - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form.
544
+ - [`TanStack Form`](https://github.com/TanStack/form): Headless, performant, and type-safe form state management for TS/JS, React, Vue, Angular, Solid, and Lit
543
545
  - [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s.
544
546
  - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod.
545
547
  - [`react-zorm`](https://github.com/esamattis/react-zorm): Standalone `<form>` generation and validation for React using Zod.
@@ -612,6 +614,8 @@ There are a growing number of tools that are built atop or support Zod natively!
612
614
  - [`zod-config`](https://github.com/alexmarqs/zod-config): Load configurations across multiple sources with flexible adapters, ensuring type safety with Zod.
613
615
  - [`unplugin-environment`](https://github.com/r17x/js/tree/main/packages/unplugin-environment#readme): A plugin for loading enviroment variables safely with schema validation, simple with virtual module, type-safe with intellisense, and better DX 🔥 🚀 👷. Powered by Zod.
614
616
  - [`zod-struct`](https://codeberg.org/reesericci/zod-struct): Create runtime-checked structs with Zod.
617
+ - [`zod-csv`](https://github.com/bartoszgolebiowski/zod-csv): Validation helpers for zod for parsing CSV data.
618
+ - [`fullproduct.dev`](https://fullproduct.dev?identity=freelancers&v=z3): Universal Expo + Next.js App Starter that uses Zod schemas as the single source of truth to keep generated MDX docs, GraphQL, database models, forms, and fetcher functions in sync.
615
619
 
616
620
  #### Utilities for Zod
617
621
 
@@ -621,6 +625,8 @@ There are a growing number of tools that are built atop or support Zod natively!
621
625
  - [`zod-dev`](https://github.com/schalkventer/zod-dev): Conditionally disables Zod runtime parsing in production.
622
626
  - [`zod-accelerator`](https://github.com/duplojs/duplojs-zod-accelerator): Accelerates Zod's throughput up to ~100x.
623
627
 
628
+ <br/>
629
+
624
630
  ## Installation
625
631
 
626
632
  ### Requirements
@@ -661,6 +667,8 @@ pnpm add zod@canary # pnpm
661
667
 
662
668
  > The rest of this README assumes you are using npm and importing directly from the `"zod"` package.
663
669
 
670
+ <br/>
671
+
664
672
  ## Basic usage
665
673
 
666
674
  Creating a simple string schema
@@ -696,6 +704,8 @@ type User = z.infer<typeof User>;
696
704
  // { username: string }
697
705
  ```
698
706
 
707
+ <br/>
708
+
699
709
  ## Primitives
700
710
 
701
711
  ```ts
@@ -724,6 +734,8 @@ z.unknown();
724
734
  z.never();
725
735
  ```
726
736
 
737
+ <br/>
738
+
727
739
  ## Coercion for primitives
728
740
 
729
741
  Zod now provides a more convenient way to coerce primitive values.
@@ -780,6 +792,8 @@ schema.parse(null); // => false
780
792
 
781
793
  For more control over coercion logic, consider using [`z.preprocess`](#preprocess) or [`z.pipe()`](#pipe).
782
794
 
795
+ <br/>
796
+
783
797
  ## Literals
784
798
 
785
799
  Literal schemas represent a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types), like `"hello world"` or `5`.
@@ -799,6 +813,8 @@ tuna.value; // "tuna"
799
813
 
800
814
  > Currently there is no support for Date literals in Zod. If you have a use case for this feature, please file an issue.
801
815
 
816
+ <br/>
817
+
802
818
  ## Strings
803
819
 
804
820
  Zod includes a handful of string-specific validations.
@@ -831,7 +847,7 @@ z.string().toUpperCase(); // toUpperCase
831
847
 
832
848
  // added in Zod 3.23
833
849
  z.string().date(); // ISO date format (YYYY-MM-DD)
834
- z.string().time(); // ISO time format (HH:mm:ss[.SSSSSS])
850
+ z.string().time(); // ISO time format (HH:mm:ss[.SSSSSS] or HH:mm)
835
851
  z.string().duration(); // ISO 8601 duration
836
852
  z.string().base64();
837
853
  ```
@@ -871,7 +887,7 @@ z.string().cidr({ message: "Invalid CIDR" });
871
887
 
872
888
  As you may have noticed, Zod string includes a few date/time related validations. These validations are regular expression based, so they are not as strict as a full date/time library. However, they are very convenient for validating user input.
873
889
 
874
- The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision.
890
+ The `z.string().datetime()` method enforces ISO 8601; default is no timezone offsets and arbitrary sub-second decimal precision. Seconds may be omitted if precision is not set.
875
891
 
876
892
  ```ts
877
893
  const datetime = z.string().datetime();
@@ -879,6 +895,7 @@ const datetime = z.string().datetime();
879
895
  datetime.parse("2020-01-01T00:00:00Z"); // pass
880
896
  datetime.parse("2020-01-01T00:00:00.123Z"); // pass
881
897
  datetime.parse("2020-01-01T00:00:00.123456Z"); // pass (arbitrary precision)
898
+ datetime.parse("2020-01-01T00:00Z"); // pass (hours and minutes only)
882
899
  datetime.parse("2020-01-01T00:00:00+02:00"); // fail (no offsets allowed)
883
900
  ```
884
901
 
@@ -888,6 +905,7 @@ Timezone offsets can be allowed by setting the `offset` option to `true`.
888
905
  const datetime = z.string().datetime({ offset: true });
889
906
 
890
907
  datetime.parse("2020-01-01T00:00:00+02:00"); // pass
908
+ datetime.parse("2020-01-01T00:00+02:00"); // pass
891
909
  datetime.parse("2020-01-01T00:00:00.123+02:00"); // pass (millis optional)
892
910
  datetime.parse("2020-01-01T00:00:00.123+0200"); // pass (millis optional)
893
911
  datetime.parse("2020-01-01T00:00:00.123+02"); // pass (only offset hours)
@@ -899,6 +917,7 @@ Allow unqualified (timezone-less) datetimes with the `local` flag.
899
917
  ```ts
900
918
  const schema = z.string().datetime({ local: true });
901
919
  schema.parse("2020-01-01T00:00:00"); // pass
920
+ schema.parse("2020-01-01T00:00"); // pass
902
921
  ```
903
922
 
904
923
  You can additionally constrain the allowable `precision`. By default, arbitrary sub-second precision is supported (but optional).
@@ -908,6 +927,7 @@ const datetime = z.string().datetime({ precision: 3 });
908
927
 
909
928
  datetime.parse("2020-01-01T00:00:00.123Z"); // pass
910
929
  datetime.parse("2020-01-01T00:00:00Z"); // fail
930
+ datetime.parse("2020-01-01T00:00Z"); // fail
911
931
  datetime.parse("2020-01-01T00:00:00.123456Z"); // fail
912
932
  ```
913
933
 
@@ -929,13 +949,14 @@ date.parse("2020-01-32"); // fail
929
949
 
930
950
  > Added in Zod 3.23
931
951
 
932
- The `z.string().time()` method validates strings in the format `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.
952
+ The `z.string().time()` method validates strings in the format `HH:MM` or `HH:MM:SS[.s+]`. The second can include arbitrary decimal precision. It does not allow timezone offsets of any kind.
933
953
 
934
954
  ```ts
935
955
  const time = z.string().time();
936
956
 
937
957
  time.parse("00:00:00"); // pass
938
958
  time.parse("09:52:31"); // pass
959
+ time.parse("09:52"); // pass
939
960
  time.parse("23:59:59.9999999"); // pass (arbitrary precision)
940
961
 
941
962
  time.parse("00:00:00.123Z"); // fail (no `Z` allowed)
@@ -950,6 +971,7 @@ const time = z.string().time({ precision: 3 });
950
971
  time.parse("00:00:00.123"); // pass
951
972
  time.parse("00:00:00.123456"); // fail
952
973
  time.parse("00:00:00"); // fail
974
+ time.parse("00:00"); // fail
953
975
  ```
954
976
 
955
977
  ### IP addresses
@@ -997,6 +1019,8 @@ const ipv6Cidr = z.string().cidr({ version: "v6" });
997
1019
  ipv6Cidr.parse("192.168.1.1"); // fail
998
1020
  ```
999
1021
 
1022
+ <br/>
1023
+
1000
1024
  ## Numbers
1001
1025
 
1002
1026
  You can customize certain error messages when creating a number schema.
@@ -1035,6 +1059,8 @@ Optionally, you can pass in a second argument to provide a custom error message.
1035
1059
  z.number().lte(5, { message: "this👏is👏too👏big" });
1036
1060
  ```
1037
1061
 
1062
+ <br/>
1063
+
1038
1064
  ## BigInts
1039
1065
 
1040
1066
  Zod includes a handful of bigint-specific validations.
@@ -1053,6 +1079,8 @@ z.bigint().nonpositive(); // <= 0n
1053
1079
  z.bigint().multipleOf(5n); // Evenly divisible by 5n.
1054
1080
  ```
1055
1081
 
1082
+ <br/>
1083
+
1056
1084
  ## NaNs
1057
1085
 
1058
1086
  You can customize certain error messages when creating a nan schema.
@@ -1064,6 +1092,8 @@ const isNaN = z.nan({
1064
1092
  });
1065
1093
  ```
1066
1094
 
1095
+ <br/>
1096
+
1067
1097
  ## Booleans
1068
1098
 
1069
1099
  You can customize certain error messages when creating a boolean schema.
@@ -1075,6 +1105,8 @@ const isActive = z.boolean({
1075
1105
  });
1076
1106
  ```
1077
1107
 
1108
+ <br/>
1109
+
1078
1110
  ## Dates
1079
1111
 
1080
1112
  Use z.date() to validate `Date` instances.
@@ -1122,6 +1154,8 @@ console.log(dateSchema.safeParse("0000-00-00").success); // false
1122
1154
 
1123
1155
  For older zod versions, use [`z.preprocess`](#preprocess) like [described in this thread](https://github.com/colinhacks/zod/discussions/879#discussioncomment-2036276).
1124
1156
 
1157
+ <br/>
1158
+
1125
1159
  ## Zod enums
1126
1160
 
1127
1161
  ```ts
@@ -1177,6 +1211,8 @@ const SalmonAndTrout = FishEnum.extract(["Salmon", "Trout"]);
1177
1211
  const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);
1178
1212
  ```
1179
1213
 
1214
+ <br/>
1215
+
1180
1216
  ## Native enums
1181
1217
 
1182
1218
  Zod enums are the recommended approach to defining and validating enums. But if you need to validate against an enum from a third-party library (or you don't want to rewrite your existing enums) you can use `z.nativeEnum()`.
@@ -1245,6 +1281,8 @@ You can access the underlying object with the `.enum` property:
1245
1281
  FruitEnum.enum.Apple; // "apple"
1246
1282
  ```
1247
1283
 
1284
+ <br/>
1285
+
1248
1286
  ## Optionals
1249
1287
 
1250
1288
  You can make any schema optional with `z.optional()`. This wraps the schema in a `ZodOptional` instance and returns the result.
@@ -1273,6 +1311,8 @@ const optionalString = stringSchema.optional();
1273
1311
  optionalString.unwrap() === stringSchema; // true
1274
1312
  ```
1275
1313
 
1314
+ <br/>
1315
+
1276
1316
  ## Nullables
1277
1317
 
1278
1318
  Similarly, you can create nullable types with `z.nullable()`.
@@ -1298,6 +1338,8 @@ const nullableString = stringSchema.nullable();
1298
1338
  nullableString.unwrap() === stringSchema; // true
1299
1339
  ```
1300
1340
 
1341
+ <br/>
1342
+
1301
1343
  ## Objects
1302
1344
 
1303
1345
  ```ts
@@ -1566,6 +1608,8 @@ person.parse({
1566
1608
 
1567
1609
  Using `.catchall()` obviates `.passthrough()` , `.strip()` , or `.strict()`. All keys are now considered "known".
1568
1610
 
1611
+ <br/>
1612
+
1569
1613
  ## Arrays
1570
1614
 
1571
1615
  ```ts
@@ -1622,6 +1666,8 @@ z.string().array().length(5); // must contain 5 items exactly
1622
1666
 
1623
1667
  Unlike `.nonempty()` these methods do not change the inferred type.
1624
1668
 
1669
+ <br/>
1670
+
1625
1671
  ## Tuples
1626
1672
 
1627
1673
  Unlike arrays, tuples have a fixed number of elements and each element can have a different type.
@@ -1647,6 +1693,8 @@ const result = variadicTuple.parse(["hello", 1, 2, 3]);
1647
1693
  // => [string, ...number[]];
1648
1694
  ```
1649
1695
 
1696
+ <br/>
1697
+
1650
1698
  ## Unions
1651
1699
 
1652
1700
  Zod includes a built-in `z.union` method for composing "OR" types.
@@ -1682,6 +1730,8 @@ console.log(optionalUrl.safeParse("https://zod.dev").success); // true
1682
1730
  console.log(optionalUrl.safeParse("not a valid url").success); // false
1683
1731
  ```
1684
1732
 
1733
+ <br/>
1734
+
1685
1735
  ## Discriminated unions
1686
1736
 
1687
1737
  A discriminated union is a union of object schemas that all share a particular key.
@@ -1724,6 +1774,8 @@ const B = z.discriminatedUnion("status", [
1724
1774
  const AB = z.discriminatedUnion("status", [...A.options, ...B.options]);
1725
1775
  ```
1726
1776
 
1777
+ <br/>
1778
+
1727
1779
  ## Records
1728
1780
 
1729
1781
  Record schemas are used to validate types such as `Record<string, number>`. This is particularly useful for storing or caching items by ID.
@@ -1778,6 +1830,8 @@ for (const key in testMap) {
1778
1830
 
1779
1831
  As you can see, JavaScript automatically casts all object keys to strings under the hood. Since Zod is trying to bridge the gap between static and runtime types, it doesn't make sense to provide a way of creating a record schema with numerical keys, since there's no such thing as a numerical key in runtime JavaScript.
1780
1832
 
1833
+ <br/>
1834
+
1781
1835
  ## Maps
1782
1836
 
1783
1837
  ```ts
@@ -1787,6 +1841,8 @@ type StringNumberMap = z.infer<typeof stringNumberMap>;
1787
1841
  // type StringNumberMap = Map<string, number>
1788
1842
  ```
1789
1843
 
1844
+ <br/>
1845
+
1790
1846
  ## Sets
1791
1847
 
1792
1848
  ```ts
@@ -1804,6 +1860,8 @@ z.set(z.string()).max(5); // must contain 5 or fewer items
1804
1860
  z.set(z.string()).size(5); // must contain 5 items exactly
1805
1861
  ```
1806
1862
 
1863
+ <br/>
1864
+
1807
1865
  ## Intersections
1808
1866
 
1809
1867
  Intersections are useful for creating "logical AND" types. This is useful for intersecting two object types.
@@ -1852,6 +1910,8 @@ type Teacher = z.infer<typeof Teacher>;
1852
1910
  // { id:string; name:string };
1853
1911
  ``` -->
1854
1912
 
1913
+ <br/>
1914
+
1855
1915
  ## Recursive types
1856
1916
 
1857
1917
  You can define a recursive schema in Zod, but because of a limitation of TypeScript, their type can't be statically inferred. Instead you'll need to define the type definition manually, and provide it to Zod as a "type hint".
@@ -1942,6 +2002,8 @@ Despite supporting recursive schemas, passing cyclical data into Zod will cause
1942
2002
 
1943
2003
  > To detect cyclical objects before they cause problems, consider [this approach](https://gist.github.com/colinhacks/d35825e505e635df27cc950776c5500b).
1944
2004
 
2005
+ <br/>
2006
+
1945
2007
  ## Promises
1946
2008
 
1947
2009
  ```ts
@@ -1973,6 +2035,8 @@ const test = async () => {
1973
2035
 
1974
2036
  When "parsing" a promise, Zod checks that the passed value is an object with `.then` and `.catch` methods — that's it. So you should be able to pass non-native Promises (Bluebird, etc) into `z.promise(...).parse` with no trouble. One gotcha: the return type of the parse function will be a _native_ `Promise` , so if you have downstream logic that uses non-standard Promise methods, this won't work. -->
1975
2037
 
2038
+ <br/>
2039
+
1976
2040
  ## Instanceof
1977
2041
 
1978
2042
  You can use `z.instanceof` to check that the input is an instance of a class. This is useful to validate inputs against classes that are exported from third-party libraries.
@@ -1989,6 +2053,8 @@ TestSchema.parse(new Test()); // passes
1989
2053
  TestSchema.parse(blob); // throws
1990
2054
  ```
1991
2055
 
2056
+ <br/>
2057
+
1992
2058
  ## Functions
1993
2059
 
1994
2060
  Zod also lets you define "function schemas". This makes it easy to validate the inputs and outputs of a function without intermixing your validation code and "business logic".
@@ -2072,6 +2138,8 @@ myFunction.returnType();
2072
2138
  * `args: ZodTuple` The first argument is a tuple (created with `z.tuple([...])` and defines the schema of the arguments to your function. If the function doesn't accept arguments, you can pass an empty tuple (`z.tuple([])`).
2073
2139
  * `returnType: any Zod schema` The second argument is the function's return type. This can be any Zod schema. -->
2074
2140
 
2141
+ <br/>
2142
+
2075
2143
  ## Preprocess
2076
2144
 
2077
2145
  > Zod now supports primitive coercion without the need for `.preprocess()`. See the [coercion docs](#coercion-for-primitives) for more information.
@@ -2086,6 +2154,8 @@ const castToString = z.preprocess((val) => String(val), z.string());
2086
2154
 
2087
2155
  This returns a `ZodEffects` instance. `ZodEffects` is a wrapper class that contains all logic pertaining to preprocessing, refinements, and transforms.
2088
2156
 
2157
+ <br/>
2158
+
2089
2159
  ## Custom schemas
2090
2160
 
2091
2161
  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.
@@ -2113,6 +2183,8 @@ You can customize the error message and other options by passing a second argume
2113
2183
  z.custom<...>((val) => ..., "custom error message");
2114
2184
  ```
2115
2185
 
2186
+ <br/>
2187
+
2116
2188
  ## Schema methods
2117
2189
 
2118
2190
  All Zod schemas contain certain methods.
@@ -2490,8 +2562,8 @@ numberWithRandomDefault.parse(undefined); // => 0.7223408162401552
2490
2562
 
2491
2563
  Conceptually, this is how Zod processes default values:
2492
2564
 
2493
- 1. If the input is `undefined`, the default value is returned
2494
- 2. Otherwise, the data is parsed using the base schema
2565
+ 1. If the input is `undefined`, the default value is substituted
2566
+ 2. Then the data is parsed using the base schema. Your default value will be parsed by the schema (including any potential transforms).
2495
2567
 
2496
2568
  ### `.describe`
2497
2569
 
@@ -2698,61 +2770,7 @@ z.string()
2698
2770
 
2699
2771
  The `.pipe()` method returns a `ZodPipeline` instance.
2700
2772
 
2701
- #### You can use `.pipe()` to fix common issues with `z.coerce`.
2702
-
2703
- You can constrain the input to types that work well with your chosen coercion. Then use `.pipe()` to apply the coercion.
2704
-
2705
- without constrained input:
2706
-
2707
- ```ts
2708
- const toDate = z.coerce.date();
2709
-
2710
- // works intuitively
2711
- console.log(toDate.safeParse("2023-01-01").success); // true
2712
-
2713
- // might not be what you want
2714
- console.log(toDate.safeParse(null).success); // true
2715
- ```
2716
-
2717
- with constrained input:
2718
-
2719
- ```ts
2720
- const datelike = z.union([z.number(), z.string(), z.date()]);
2721
- const datelikeToDate = datelike.pipe(z.coerce.date());
2722
-
2723
- // still works intuitively
2724
- console.log(datelikeToDate.safeParse("2023-01-01").success); // true
2725
-
2726
- // more likely what you want
2727
- console.log(datelikeToDate.safeParse(null).success); // false
2728
- ```
2729
-
2730
- You can also use this technique to avoid coercions that throw uncaught errors.
2731
-
2732
- without constrained input:
2733
-
2734
- ```ts
2735
- const toBigInt = z.coerce.bigint();
2736
-
2737
- // works intuitively
2738
- console.log(toBigInt.safeParse("42")); // true
2739
-
2740
- // probably not what you want
2741
- console.log(toBigInt.safeParse(null)); // throws uncaught error
2742
- ```
2743
-
2744
- with constrained input:
2745
-
2746
- ```ts
2747
- const toNumber = z.number().or(z.string()).pipe(z.coerce.number());
2748
- const toBigInt = z.bigint().or(toNumber).pipe(z.coerce.bigint());
2749
-
2750
- // still works intuitively
2751
- console.log(toBigInt.safeParse("42").success); // true
2752
-
2753
- // error handled by zod, more likely what you want
2754
- console.log(toBigInt.safeParse(null).success); // false
2755
- ```
2773
+ <br/>
2756
2774
 
2757
2775
  ## Guides and concepts
2758
2776
 
@@ -2923,6 +2941,8 @@ if (!result.success) {
2923
2941
  }
2924
2942
  ```
2925
2943
 
2944
+ <br/>
2945
+
2926
2946
  ## Comparison
2927
2947
 
2928
2948
  There are a handful of other widely-used validation libraries, but all of them have certain design limitations that make for a non-ideal developer experience.
@@ -3069,6 +3089,8 @@ Ow is focused on function input validation. It's a library that makes it easy to
3069
3089
 
3070
3090
  If you want to validate function inputs, use function schemas in Zod! It's a much simpler approach that lets you reuse a function type declaration without repeating yourself (namely, copy-pasting a bunch of ow assertions at the beginning of every function). Also Zod lets you validate your return types as well, so you can be sure there won't be any unexpected data passed downstream.
3071
3091
 
3092
+ <br/>
3093
+
3072
3094
  ## Changelog
3073
3095
 
3074
3096
  View the changelog at [CHANGELOG.md](CHANGELOG.md)
@@ -22,7 +22,7 @@ export declare namespace util {
22
22
  export {};
23
23
  }
24
24
  export declare namespace objectUtil {
25
- export type MergeShapes<U, V> = {
25
+ export type MergeShapes<U, V> = keyof U & keyof V extends never ? U & V : {
26
26
  [k in Exclude<keyof U, keyof V>]: U[k];
27
27
  } & V;
28
28
  type optionalKeys<T extends object> = {
@@ -49,7 +49,7 @@ export declare namespace objectUtil {
49
49
  [k in noNeverKeys<T>]: k extends keyof T ? T[k] : never;
50
50
  }>;
51
51
  export const mergeShapes: <U, T>(first: U, second: T) => T & U;
52
- export type extendShape<A extends object, B extends object> = {
52
+ export type extendShape<A extends object, B extends object> = keyof A & keyof B extends never ? A & B : {
53
53
  [K in keyof A as K extends keyof B ? never : K]: A[K];
54
54
  } & {
55
55
  [K in keyof B]: B[K];
package/lib/index.mjs CHANGED
@@ -961,15 +961,15 @@ const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z
961
961
  const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
962
962
  const dateRegex = new RegExp(`^${dateRegexSource}$`);
963
963
  function timeRegexSource(args) {
964
- // let regex = `\\d{2}:\\d{2}:\\d{2}`;
965
- let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
964
+ let secondsRegexSource = `[0-5]\\d`;
966
965
  if (args.precision) {
967
- regex = `${regex}\\.\\d{${args.precision}}`;
966
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
968
967
  }
969
968
  else if (args.precision == null) {
970
- regex = `${regex}(\\.\\d+)?`;
969
+ secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
971
970
  }
972
- return regex;
971
+ const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero
972
+ return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
973
973
  }
974
974
  function timeRegex(args) {
975
975
  return new RegExp(`^${timeRegexSource(args)}$`);
package/lib/index.umd.js CHANGED
@@ -967,15 +967,15 @@
967
967
  const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
968
968
  const dateRegex = new RegExp(`^${dateRegexSource}$`);
969
969
  function timeRegexSource(args) {
970
- // let regex = `\\d{2}:\\d{2}:\\d{2}`;
971
- let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
970
+ let secondsRegexSource = `[0-5]\\d`;
972
971
  if (args.precision) {
973
- regex = `${regex}\\.\\d{${args.precision}}`;
972
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
974
973
  }
975
974
  else if (args.precision == null) {
976
- regex = `${regex}(\\.\\d+)?`;
975
+ secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
977
976
  }
978
- return regex;
977
+ const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero
978
+ return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
979
979
  }
980
980
  function timeRegex(args) {
981
981
  return new RegExp(`^${timeRegexSource(args)}$`);
package/lib/types.js CHANGED
@@ -432,15 +432,15 @@ const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z
432
432
  const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
433
433
  const dateRegex = new RegExp(`^${dateRegexSource}$`);
434
434
  function timeRegexSource(args) {
435
- // let regex = `\\d{2}:\\d{2}:\\d{2}`;
436
- let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
435
+ let secondsRegexSource = `[0-5]\\d`;
437
436
  if (args.precision) {
438
- regex = `${regex}\\.\\d{${args.precision}}`;
437
+ secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
439
438
  }
440
439
  else if (args.precision == null) {
441
- regex = `${regex}(\\.\\d+)?`;
440
+ secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
442
441
  }
443
- return regex;
442
+ const secondsQuantifier = args.precision ? "+" : "?"; // require seconds if precision is nonzero
443
+ return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
444
444
  }
445
445
  function timeRegex(args) {
446
446
  return new RegExp(`^${timeRegexSource(args)}$`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod",
3
- "version": "3.24.2",
3
+ "version": "3.24.4",
4
4
  "author": "Colin McDonnell <colin@colinhacks.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,7 +43,7 @@
43
43
  "ts-morph": "^14.0.0",
44
44
  "ts-node": "^10.9.1",
45
45
  "tslib": "^2.3.1",
46
- "tsx": "^3.8.0",
46
+ "tsx": "^4.19.4",
47
47
  "typescript": "^5.0.0",
48
48
  "vitest": "^0.32.2"
49
49
  },