zod 4.5.3 → 4.6.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.
Files changed (348) hide show
  1. package/compile.cjs +19 -0
  2. package/index.cjs +19 -0
  3. package/locales/index.cjs +19 -0
  4. package/mini/index.cjs +19 -0
  5. package/package.json +8 -7
  6. package/src/v3/helpers/errorUtil.ts +1 -1
  7. package/src/v4/classic/checks.ts +0 -1
  8. package/src/v4/classic/external.ts +2 -0
  9. package/src/v4/classic/from-json-schema.ts +248 -25
  10. package/src/v4/classic/schemas.ts +255 -164
  11. package/src/v4/classic/tests/assignability.test.ts +59 -9
  12. package/src/v4/classic/tests/bigint.test.ts +6 -0
  13. package/src/v4/classic/tests/continuability.test.ts +2 -2
  14. package/src/v4/classic/tests/cyclic-data.test.ts +316 -0
  15. package/src/v4/classic/tests/default.test.ts +46 -0
  16. package/src/v4/classic/tests/enum.test.ts +9 -0
  17. package/src/v4/classic/tests/error.test.ts +130 -1
  18. package/src/v4/classic/tests/firstparty.test.ts +4 -0
  19. package/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  20. package/src/v4/classic/tests/iban.test.ts +81 -0
  21. package/src/v4/classic/tests/instance-footprint.test.ts +18 -2
  22. package/src/v4/classic/tests/instanceof.test.ts +27 -7
  23. package/src/v4/classic/tests/issue-schema.test.ts +88 -56
  24. package/src/v4/classic/tests/object.test.ts +56 -0
  25. package/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  26. package/src/v4/classic/tests/properties.test.ts +225 -0
  27. package/src/v4/classic/tests/recursive-types.test.ts +1 -1
  28. package/src/v4/classic/tests/standard-schema.test.ts +19 -0
  29. package/src/v4/classic/tests/string.test.ts +25 -0
  30. package/src/v4/classic/tests/template-literal.test.ts +33 -1
  31. package/src/v4/classic/tests/to-json-schema.test.ts +147 -3
  32. package/src/v4/classic/tests/validate.test.ts +569 -0
  33. package/src/v4/core/api.ts +30 -6
  34. package/src/v4/core/checks.ts +1 -101
  35. package/src/v4/core/compile.ts +193 -81
  36. package/src/v4/core/doc.ts +6 -2
  37. package/src/v4/core/errors.ts +3 -6
  38. package/src/v4/core/json-schema-generator.ts +2 -2
  39. package/src/v4/core/json-schema-processors.ts +226 -68
  40. package/src/v4/core/memoizer.ts +162 -36
  41. package/src/v4/core/parse.ts +37 -16
  42. package/src/v4/core/regexes.ts +10 -4
  43. package/src/v4/core/schemas.ts +314 -83
  44. package/src/v4/core/tests/cached.test.ts +54 -0
  45. package/src/v4/core/tests/compile-generative.test.ts +445 -0
  46. package/src/v4/core/tests/compile.test.ts +222 -2
  47. package/src/v4/core/tests/email-regex.test.ts +140 -0
  48. package/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  49. package/src/v4/core/to-json-schema.ts +10 -8
  50. package/src/v4/core/util.ts +222 -147
  51. package/src/v4/core/versions.ts +2 -2
  52. package/src/v4/core/visit.ts +11 -0
  53. package/src/v4/locales/ar.ts +1 -0
  54. package/src/v4/locales/az.ts +1 -0
  55. package/src/v4/locales/be.ts +1 -0
  56. package/src/v4/locales/bg.ts +1 -0
  57. package/src/v4/locales/bn.ts +1 -0
  58. package/src/v4/locales/ca.ts +1 -0
  59. package/src/v4/locales/ckb.ts +1 -0
  60. package/src/v4/locales/cs.ts +1 -0
  61. package/src/v4/locales/da.ts +1 -0
  62. package/src/v4/locales/de.ts +1 -0
  63. package/src/v4/locales/el.ts +1 -0
  64. package/src/v4/locales/en.ts +1 -0
  65. package/src/v4/locales/eo.ts +1 -0
  66. package/src/v4/locales/es.ts +1 -0
  67. package/src/v4/locales/fa.ts +1 -0
  68. package/src/v4/locales/fi.ts +1 -0
  69. package/src/v4/locales/fr-CA.ts +1 -0
  70. package/src/v4/locales/fr.ts +1 -0
  71. package/src/v4/locales/gu.ts +1 -0
  72. package/src/v4/locales/he.ts +1 -0
  73. package/src/v4/locales/hi.ts +1 -0
  74. package/src/v4/locales/hr.ts +1 -0
  75. package/src/v4/locales/hu.ts +1 -0
  76. package/src/v4/locales/hy.ts +1 -0
  77. package/src/v4/locales/id.ts +1 -0
  78. package/src/v4/locales/is.ts +1 -0
  79. package/src/v4/locales/it.ts +1 -0
  80. package/src/v4/locales/ja.ts +1 -0
  81. package/src/v4/locales/ka.ts +1 -0
  82. package/src/v4/locales/km.ts +1 -0
  83. package/src/v4/locales/kn.ts +1 -0
  84. package/src/v4/locales/ko.ts +1 -0
  85. package/src/v4/locales/lt.ts +1 -0
  86. package/src/v4/locales/mk.ts +1 -0
  87. package/src/v4/locales/ms.ts +1 -0
  88. package/src/v4/locales/ne.ts +1 -0
  89. package/src/v4/locales/nl.ts +1 -0
  90. package/src/v4/locales/nn.ts +1 -0
  91. package/src/v4/locales/no.ts +1 -0
  92. package/src/v4/locales/ota.ts +1 -0
  93. package/src/v4/locales/pl.ts +1 -0
  94. package/src/v4/locales/ps.ts +1 -0
  95. package/src/v4/locales/pt-BR.ts +1 -0
  96. package/src/v4/locales/pt.ts +1 -0
  97. package/src/v4/locales/ro.ts +1 -0
  98. package/src/v4/locales/ru.ts +1 -0
  99. package/src/v4/locales/sk.ts +1 -0
  100. package/src/v4/locales/sl.ts +1 -0
  101. package/src/v4/locales/sv.ts +1 -0
  102. package/src/v4/locales/ta.ts +1 -0
  103. package/src/v4/locales/th.ts +1 -0
  104. package/src/v4/locales/tk.ts +1 -0
  105. package/src/v4/locales/tr.ts +1 -0
  106. package/src/v4/locales/uk.ts +1 -0
  107. package/src/v4/locales/ur.ts +1 -0
  108. package/src/v4/locales/uz.ts +1 -0
  109. package/src/v4/locales/vi.ts +1 -0
  110. package/src/v4/locales/yo.ts +1 -0
  111. package/src/v4/locales/zh-CN.ts +1 -0
  112. package/src/v4/locales/zh-TW.ts +1 -0
  113. package/src/v4/mini/checks.ts +0 -1
  114. package/src/v4/mini/external.ts +2 -0
  115. package/src/v4/mini/schemas.ts +38 -2
  116. package/src/v4/mini/tests/checks.test.ts +1 -1
  117. package/src/v4/mini/tests/computed.test.ts +11 -17
  118. package/src/v4/mini/tests/index.test.ts +8 -0
  119. package/src/v4/mini/tests/string.test.ts +16 -0
  120. package/v3/ZodError.cjs +19 -0
  121. package/v3/errors.cjs +19 -0
  122. package/v3/external.cjs +19 -0
  123. package/v3/helpers/enumUtil.cjs +19 -0
  124. package/v3/helpers/errorUtil.cjs +20 -1
  125. package/v3/helpers/errorUtil.js +1 -1
  126. package/v3/helpers/parseUtil.cjs +19 -0
  127. package/v3/helpers/partialUtil.cjs +19 -0
  128. package/v3/helpers/typeAliases.cjs +19 -0
  129. package/v3/helpers/util.cjs +19 -0
  130. package/v3/index.cjs +19 -0
  131. package/v3/standard-schema.cjs +19 -0
  132. package/v3/types.cjs +19 -0
  133. package/v4/classic/checks.cjs +20 -2
  134. package/v4/classic/checks.d.cts +1 -1
  135. package/v4/classic/checks.d.ts +1 -1
  136. package/v4/classic/checks.js +1 -1
  137. package/v4/classic/coerce.cjs +19 -0
  138. package/v4/classic/compat.cjs +19 -0
  139. package/v4/classic/deep-partial.cjs +19 -0
  140. package/v4/classic/errors.cjs +19 -0
  141. package/v4/classic/external.cjs +22 -1
  142. package/v4/classic/external.d.cts +1 -1
  143. package/v4/classic/external.d.ts +1 -1
  144. package/v4/classic/external.js +1 -1
  145. package/v4/classic/from-json-schema.cjs +264 -24
  146. package/v4/classic/from-json-schema.js +245 -24
  147. package/v4/classic/in-out.cjs +19 -0
  148. package/v4/classic/index.cjs +19 -0
  149. package/v4/classic/iso.cjs +19 -0
  150. package/v4/classic/parse.cjs +19 -0
  151. package/v4/classic/schemas.cjs +100 -31
  152. package/v4/classic/schemas.d.cts +17 -1
  153. package/v4/classic/schemas.d.ts +17 -1
  154. package/v4/classic/schemas.js +77 -29
  155. package/v4/core/api.cjs +37 -2
  156. package/v4/core/api.d.cts +6 -4
  157. package/v4/core/api.d.ts +6 -4
  158. package/v4/core/api.js +17 -2
  159. package/v4/core/checks.cjs +19 -96
  160. package/v4/core/checks.d.cts +1 -1
  161. package/v4/core/checks.d.ts +1 -1
  162. package/v4/core/checks.js +0 -96
  163. package/v4/core/compile.cjs +164 -65
  164. package/v4/core/compile.d.cts +18 -4
  165. package/v4/core/compile.d.ts +18 -4
  166. package/v4/core/compile.js +145 -66
  167. package/v4/core/core.cjs +19 -0
  168. package/v4/core/doc.cjs +26 -2
  169. package/v4/core/doc.js +7 -2
  170. package/v4/core/errors.cjs +21 -5
  171. package/v4/core/errors.js +2 -5
  172. package/v4/core/index.cjs +19 -0
  173. package/v4/core/json-schema-generator.cjs +20 -1
  174. package/v4/core/json-schema-generator.js +2 -2
  175. package/v4/core/json-schema-processors.cjs +215 -63
  176. package/v4/core/json-schema-processors.d.cts +17 -0
  177. package/v4/core/json-schema-processors.d.ts +17 -0
  178. package/v4/core/json-schema-processors.js +195 -64
  179. package/v4/core/json-schema.cjs +19 -0
  180. package/v4/core/memoizer.cjs +204 -36
  181. package/v4/core/memoizer.js +162 -36
  182. package/v4/core/parse.cjs +56 -16
  183. package/v4/core/parse.js +37 -16
  184. package/v4/core/regexes.cjs +29 -6
  185. package/v4/core/regexes.d.cts +2 -0
  186. package/v4/core/regexes.d.ts +2 -0
  187. package/v4/core/regexes.js +8 -4
  188. package/v4/core/registries.cjs +19 -0
  189. package/v4/core/schemas.cjs +285 -66
  190. package/v4/core/schemas.d.cts +34 -3
  191. package/v4/core/schemas.d.ts +34 -3
  192. package/v4/core/schemas.js +264 -65
  193. package/v4/core/standard-schema.cjs +19 -0
  194. package/v4/core/to-json-schema.cjs +29 -7
  195. package/v4/core/to-json-schema.d.cts +7 -3
  196. package/v4/core/to-json-schema.d.ts +7 -3
  197. package/v4/core/to-json-schema.js +8 -7
  198. package/v4/core/util.cjs +181 -143
  199. package/v4/core/util.d.cts +25 -4
  200. package/v4/core/util.d.ts +25 -4
  201. package/v4/core/util.js +160 -143
  202. package/v4/core/versions.cjs +21 -2
  203. package/v4/core/versions.d.cts +1 -1
  204. package/v4/core/versions.d.ts +1 -1
  205. package/v4/core/versions.js +2 -2
  206. package/v4/core/visit.cjs +31 -0
  207. package/v4/core/visit.js +12 -0
  208. package/v4/index.cjs +19 -0
  209. package/v4/locales/ar.cjs +1 -0
  210. package/v4/locales/ar.js +1 -0
  211. package/v4/locales/az.cjs +1 -0
  212. package/v4/locales/az.js +1 -0
  213. package/v4/locales/be.cjs +1 -0
  214. package/v4/locales/be.js +1 -0
  215. package/v4/locales/bg.cjs +1 -0
  216. package/v4/locales/bg.js +1 -0
  217. package/v4/locales/bn.cjs +1 -0
  218. package/v4/locales/bn.js +1 -0
  219. package/v4/locales/ca.cjs +1 -0
  220. package/v4/locales/ca.js +1 -0
  221. package/v4/locales/ckb.cjs +1 -0
  222. package/v4/locales/ckb.js +1 -0
  223. package/v4/locales/cs.cjs +1 -0
  224. package/v4/locales/cs.js +1 -0
  225. package/v4/locales/da.cjs +1 -0
  226. package/v4/locales/da.js +1 -0
  227. package/v4/locales/de.cjs +1 -0
  228. package/v4/locales/de.js +1 -0
  229. package/v4/locales/el.cjs +1 -0
  230. package/v4/locales/el.js +1 -0
  231. package/v4/locales/en.cjs +1 -0
  232. package/v4/locales/en.js +1 -0
  233. package/v4/locales/eo.cjs +1 -0
  234. package/v4/locales/eo.js +1 -0
  235. package/v4/locales/es.cjs +1 -0
  236. package/v4/locales/es.js +1 -0
  237. package/v4/locales/fa.cjs +1 -0
  238. package/v4/locales/fa.js +1 -0
  239. package/v4/locales/fi.cjs +1 -0
  240. package/v4/locales/fi.js +1 -0
  241. package/v4/locales/fr-CA.cjs +1 -0
  242. package/v4/locales/fr-CA.js +1 -0
  243. package/v4/locales/fr.cjs +1 -0
  244. package/v4/locales/fr.js +1 -0
  245. package/v4/locales/gu.cjs +1 -0
  246. package/v4/locales/gu.js +1 -0
  247. package/v4/locales/he.cjs +1 -0
  248. package/v4/locales/he.js +1 -0
  249. package/v4/locales/hi.cjs +1 -0
  250. package/v4/locales/hi.js +1 -0
  251. package/v4/locales/hr.cjs +1 -0
  252. package/v4/locales/hr.js +1 -0
  253. package/v4/locales/hu.cjs +1 -0
  254. package/v4/locales/hu.js +1 -0
  255. package/v4/locales/hy.cjs +1 -0
  256. package/v4/locales/hy.js +1 -0
  257. package/v4/locales/id.cjs +1 -0
  258. package/v4/locales/id.js +1 -0
  259. package/v4/locales/index.cjs +19 -0
  260. package/v4/locales/is.cjs +1 -0
  261. package/v4/locales/is.js +1 -0
  262. package/v4/locales/it.cjs +1 -0
  263. package/v4/locales/it.js +1 -0
  264. package/v4/locales/ja.cjs +1 -0
  265. package/v4/locales/ja.js +1 -0
  266. package/v4/locales/ka.cjs +1 -0
  267. package/v4/locales/ka.js +1 -0
  268. package/v4/locales/km.cjs +1 -0
  269. package/v4/locales/km.js +1 -0
  270. package/v4/locales/kn.cjs +1 -0
  271. package/v4/locales/kn.js +1 -0
  272. package/v4/locales/ko.cjs +1 -0
  273. package/v4/locales/ko.js +1 -0
  274. package/v4/locales/lt.cjs +1 -0
  275. package/v4/locales/lt.js +1 -0
  276. package/v4/locales/mk.cjs +1 -0
  277. package/v4/locales/mk.js +1 -0
  278. package/v4/locales/ms.cjs +1 -0
  279. package/v4/locales/ms.js +1 -0
  280. package/v4/locales/ne.cjs +1 -0
  281. package/v4/locales/ne.js +1 -0
  282. package/v4/locales/nl.cjs +1 -0
  283. package/v4/locales/nl.js +1 -0
  284. package/v4/locales/nn.cjs +1 -0
  285. package/v4/locales/nn.js +1 -0
  286. package/v4/locales/no.cjs +1 -0
  287. package/v4/locales/no.js +1 -0
  288. package/v4/locales/ota.cjs +1 -0
  289. package/v4/locales/ota.js +1 -0
  290. package/v4/locales/pl.cjs +1 -0
  291. package/v4/locales/pl.js +1 -0
  292. package/v4/locales/ps.cjs +1 -0
  293. package/v4/locales/ps.js +1 -0
  294. package/v4/locales/pt-BR.cjs +1 -0
  295. package/v4/locales/pt-BR.js +1 -0
  296. package/v4/locales/pt.cjs +1 -0
  297. package/v4/locales/pt.js +1 -0
  298. package/v4/locales/ro.cjs +1 -0
  299. package/v4/locales/ro.js +1 -0
  300. package/v4/locales/ru.cjs +1 -0
  301. package/v4/locales/ru.js +1 -0
  302. package/v4/locales/sk.cjs +1 -0
  303. package/v4/locales/sk.js +1 -0
  304. package/v4/locales/sl.cjs +1 -0
  305. package/v4/locales/sl.js +1 -0
  306. package/v4/locales/sv.cjs +1 -0
  307. package/v4/locales/sv.js +1 -0
  308. package/v4/locales/ta.cjs +1 -0
  309. package/v4/locales/ta.js +1 -0
  310. package/v4/locales/th.cjs +1 -0
  311. package/v4/locales/th.js +1 -0
  312. package/v4/locales/tk.cjs +1 -0
  313. package/v4/locales/tk.js +1 -0
  314. package/v4/locales/tr.cjs +1 -0
  315. package/v4/locales/tr.js +1 -0
  316. package/v4/locales/uk.cjs +1 -0
  317. package/v4/locales/uk.js +1 -0
  318. package/v4/locales/ur.cjs +1 -0
  319. package/v4/locales/ur.js +1 -0
  320. package/v4/locales/uz.cjs +1 -0
  321. package/v4/locales/uz.js +1 -0
  322. package/v4/locales/vi.cjs +1 -0
  323. package/v4/locales/vi.js +1 -0
  324. package/v4/locales/yo.cjs +1 -0
  325. package/v4/locales/yo.js +1 -0
  326. package/v4/locales/zh-CN.cjs +1 -0
  327. package/v4/locales/zh-CN.js +1 -0
  328. package/v4/locales/zh-TW.cjs +1 -0
  329. package/v4/locales/zh-TW.js +1 -0
  330. package/v4/mini/checks.cjs +20 -2
  331. package/v4/mini/checks.d.cts +1 -1
  332. package/v4/mini/checks.d.ts +1 -1
  333. package/v4/mini/checks.js +1 -1
  334. package/v4/mini/coerce.cjs +19 -0
  335. package/v4/mini/deep-partial.cjs +19 -0
  336. package/v4/mini/external.cjs +22 -1
  337. package/v4/mini/external.d.cts +1 -1
  338. package/v4/mini/external.d.ts +1 -1
  339. package/v4/mini/external.js +1 -1
  340. package/v4/mini/in-out.cjs +19 -0
  341. package/v4/mini/index.cjs +19 -0
  342. package/v4/mini/iso.cjs +19 -0
  343. package/v4/mini/parse.cjs +19 -0
  344. package/v4/mini/schemas.cjs +42 -4
  345. package/v4/mini/schemas.d.cts +8 -0
  346. package/v4/mini/schemas.d.ts +8 -0
  347. package/v4/mini/schemas.js +19 -2
  348. package/v4-mini/index.cjs +19 -0
@@ -63,14 +63,583 @@ test("validate agrees with the compiled fast path and keeps the callback bound",
63
63
 
64
64
  calls = 0;
65
65
  expect(z.validate(compiled, { name: "x" })).toBe(false);
66
+ // a user callback can throw, so its rejection is not decidable and the fallback still runs
66
67
  expect(calls).toBeLessThanOrEqual(2);
67
68
 
68
69
  expect(z.validate(compiled, { name: 42 })).toBe(false);
70
+ expect(z.validate(compiled, { name: "x" }, {})).toBe(false);
69
71
  expect(z.validate(schema, { name: "ok" })).toBe(true);
70
72
  });
71
73
 
74
+ test("the validate shortcut is taken for callback-free schemas only", () => {
75
+ const definite = (s: z.ZodType) => (z.compile(s, { strict: true }) as any)._zod.bag.validator?.definite;
76
+
77
+ // nothing here can throw, so a compiled rejection is proof the runtime would reject
78
+ expect(definite(z.object({ a: z.string().min(1), b: z.number().max(3), c: z.email() }))).toBe(true);
79
+ expect(definite(z.array(z.enum(["a", "b"])))).toBe(true);
80
+
81
+ // each of these can answer INVALID for something the interpreter throws on
82
+ expect(definite(z.object({ a: z.string().refine(() => true) }))).toBe(false);
83
+ expect(definite(z.string().transform((v) => v))).toBe(false);
84
+ expect(definite(z.custom(() => true))).toBe(false);
85
+ expect(definite(z.number().catch(0))).toBe(false);
86
+ expect(definite(z.lazy(() => z.string()))).toBe(false);
87
+ expect(
88
+ definite(
89
+ z.intersection(
90
+ z.number(),
91
+ z.number().transform((x) => x + 1)
92
+ )
93
+ )
94
+ ).toBe(false);
95
+ expect(
96
+ definite(
97
+ z.record(
98
+ z.string().transform((k) => k),
99
+ z.number()
100
+ )
101
+ )
102
+ ).toBe(false);
103
+ });
104
+
105
+ test("compiled validate keeps the fallback where INVALID is not a decidable rejection", () => {
106
+ // an intersection answers INVALID for an unmergeable merge, which the interpreter answers with a throw — a fast false would misreport a schema bug
107
+ const unmergeable = z.compile(
108
+ z.intersection(
109
+ z.number(),
110
+ z.number().transform((x) => x + 1)
111
+ ),
112
+ { strict: true }
113
+ );
114
+ expect(() => z.validate(unmergeable, 1234)).toThrow("Unmergable intersection");
115
+
116
+ // a when-gated check islands at codegen, and an island answers INVALID for an async run too
117
+ const gated = z.number().refine(() => Promise.resolve(true));
118
+ (gated._zod.def.checks![0]!._zod.def as { when?: unknown }).when = () => true;
119
+ const compiled = z.compile(z.object({ n: gated }), { strict: true });
120
+ expect(() => z.validate(compiled, { n: 3 })).toThrow(z.core.$ZodAsyncError);
121
+ expect(() => z.validate(z.object({ n: gated }), { n: 3 })).toThrow(z.core.$ZodAsyncError);
122
+
123
+ // a plain function handing back a promise answers INVALID for union parity, so a transform is never a decidable rejection
124
+ const piped = z.string().transform(() => Promise.resolve(1));
125
+ expect(() => z.validate(z.compile(piped, { strict: true }), "x")).toThrow(z.core.$ZodAsyncError);
126
+ expect(() => z.validate(piped, "x")).toThrow(z.core.$ZodAsyncError);
127
+
128
+ // a continuable child issue short-circuits the compiled intersection before its merge, but the interpreter reaches the merge and throws
129
+ const continuable = z.intersection(
130
+ z.number().min(10),
131
+ z.number().transform((x) => x + 1)
132
+ );
133
+ expect(() => z.validate(z.compile(continuable, { strict: true }), 1)).toThrow("Unmergable intersection");
134
+ expect(() => z.validate(continuable, 1)).toThrow("Unmergable intersection");
135
+ });
136
+
137
+ test("compiled validate agrees with the interpreter, verdict and throw alike", () => {
138
+ // guards the `definite` flag: a new generator that answers INVALID for something the interpreter throws on must clear it, or this fails
139
+ const thenable = () => Promise.resolve(1) as never;
140
+ const schemas: z.ZodType[] = [
141
+ z.object({ a: z.string(), b: z.number().min(1) }),
142
+ z.strictObject({ a: z.string() }),
143
+ z.array(z.string().min(1)),
144
+ z.tuple([z.string()], z.number()),
145
+ z.record(z.string(), z.number()),
146
+ // a record key compiles in its own context, so its definiteness has to be carried out
147
+ z.record(z.string().transform(thenable), z.number()),
148
+ z.record(z.email(), z.number()),
149
+ z.union([z.string(), z.number()]),
150
+ z.intersection(
151
+ z.number(),
152
+ z.number().transform((x) => x + 1)
153
+ ),
154
+ z.intersection(
155
+ z.number().min(10),
156
+ z.number().transform((x) => x + 1)
157
+ ),
158
+ // unmergeable with no user callback in it, so only the intersection itself can clear the flag
159
+ z.intersection(z.string().default("a"), z.string().default("b")),
160
+ z.lazy(() => z.object({ a: z.string() })),
161
+ z.number().catch(0),
162
+ z.nonoptional(z.string().optional()),
163
+ z.map(z.string(), z.number()),
164
+ z.set(z.string().min(2)),
165
+ z.templateLiteral(["a", z.number()]),
166
+ z.coerce.number(),
167
+ z.stringbool(),
168
+ z.string().transform(thenable),
169
+ z.union([z.string().transform(thenable), z.number()]),
170
+ z.array(z.string().transform(thenable)),
171
+ z.custom(thenable),
172
+ z.string().refine(thenable),
173
+ z.string().pipe(z.string().min(3)),
174
+ // a codec's decode is the pipe branch's transform, and a plain function can still hand back a promise
175
+ z.codec(z.string(), z.number(), { decode: thenable, encode: String }),
176
+ z.object({ first: z.string(), second: z.codec(z.string(), z.number(), { decode: thenable, encode: String }) }),
177
+ // a continuable check does not settle the interpreter's walk, so it reaches a throwing callback the compiled path short-circuits past — the first-failure exit does not cover the check chain
178
+ z
179
+ .string()
180
+ .min(5)
181
+ .refine(() => {
182
+ throw new RangeError("u");
183
+ }),
184
+ z
185
+ .string()
186
+ .min(5)
187
+ .superRefine(() => {
188
+ throw new RangeError("u");
189
+ }),
190
+ // a user callback can throw, and compiled code can reject an earlier sibling before ever reaching it
191
+ z.object({
192
+ first: z.string(),
193
+ second: z.string().refine(() => {
194
+ throw new RangeError("u");
195
+ }),
196
+ }),
197
+ z.object({
198
+ first: z.string(),
199
+ second: z.custom(() => {
200
+ throw new TypeError("u");
201
+ }),
202
+ }),
203
+ // superRefine and check take the other branch of the refine generator than refine does
204
+ z.object({
205
+ first: z.string(),
206
+ second: z.string().superRefine(() => {
207
+ throw new RangeError("u");
208
+ }),
209
+ }),
210
+ z.string().superRefine(thenable as never),
211
+ z.object({
212
+ first: z.string(),
213
+ second: z.string().transform(() => {
214
+ throw new RangeError("u");
215
+ }),
216
+ }),
217
+ z.object({ first: z.string(), second: z.custom(thenable) }),
218
+ z.tuple([
219
+ z.string(),
220
+ z.number().catch(() => {
221
+ throw new RangeError("u");
222
+ }),
223
+ ]),
224
+ ];
225
+ const inputs = [
226
+ "x",
227
+ "ab",
228
+ "",
229
+ 0,
230
+ 1,
231
+ Number.NaN,
232
+ true,
233
+ null,
234
+ undefined,
235
+ {},
236
+ { a: "x" },
237
+ { a: 1 },
238
+ [],
239
+ ["x"],
240
+ new Map(),
241
+ new Set(["a"]),
242
+ "true",
243
+ // the exposing shape: an earlier field the compiled path rejects before it reaches the throwing one
244
+ { first: 1, second: "s" },
245
+ { first: "s", second: "s" },
246
+ { first: 1 },
247
+ [1, "x"],
248
+ ["s", "x"],
249
+ ];
250
+ const outcome = (fn: () => unknown) => {
251
+ try {
252
+ return `ok:${fn()}`;
253
+ } catch (err) {
254
+ return `throw:${(err as Error)?.constructor?.name}`;
255
+ }
256
+ };
257
+
258
+ for (const schema of schemas) {
259
+ let compiled: z.ZodType;
260
+ try {
261
+ compiled = z.compile(schema, { strict: true });
262
+ } catch {
263
+ continue; // refused at codegen, so there is no fast path to disagree
264
+ }
265
+ for (const input of inputs) {
266
+ expect(
267
+ outcome(() => z.validate(compiled, input)),
268
+ `${JSON.stringify(input)} on ${schema._zod.def.type}`
269
+ ).toBe(outcome(() => z.validate(schema, input)));
270
+ }
271
+ }
272
+ });
273
+
72
274
  test("validate is exported from zod/mini", () => {
73
275
  expect(zm.validate(zm.string(), "a")).toBe(true);
74
276
  expect(zm.validate(zm.string(), 1)).toBe(false);
75
277
  expect(zm.validate(zm.object({ a: zm.number() }), { a: 1 })).toBe(true);
76
278
  });
279
+
280
+ test("the validate method matches the top-level function", () => {
281
+ expect(z.string().validate("asdf")).toBe(true);
282
+ expect(z.string().validate(12)).toBe(false);
283
+ expect(z.object({ a: z.string() }).validate({ a: "x" })).toBe(true);
284
+ expect(z.object({ a: z.string() }).validate({ a: 1 })).toBe(false);
285
+ expect(z.compile(z.object({ a: z.string() })).validate({ a: "x" })).toBe(true);
286
+ });
287
+
288
+ test("the validate method narrows to the input type", () => {
289
+ const value: unknown = "hi";
290
+ if (z.string().validate(value)) {
291
+ expectTypeOf(value).toEqualTypeOf<string>();
292
+ }
293
+ const transforming = z.string().transform((s) => s.length);
294
+ if (transforming.validate(value)) {
295
+ expectTypeOf(value).toEqualTypeOf<string>();
296
+ expectTypeOf(value).not.toEqualTypeOf<number>();
297
+ }
298
+ });
299
+
300
+ test("the validate method takes a params argument", () => {
301
+ let calls = 0;
302
+ const error = () => {
303
+ calls++;
304
+ return "bad";
305
+ };
306
+ expect(z.string().validate(12, { error })).toBe(false);
307
+ expect(z.string().validate("ok", { error })).toBe(true);
308
+ // a ctx defeats the compiled definite shortcut, so this is the fallback answering
309
+ expect(z.compile(z.string()).validate(12, { error })).toBe(false);
310
+ expect(z.string().validate("ok", { jitless: true })).toBe(true);
311
+ // no issue is ever finalized, so an error map never runs
312
+ expect(calls).toBe(0);
313
+ });
314
+
315
+ test("the validateAsync method handles async schemas the method form throws on", async () => {
316
+ const schema = z.string().refine(async (s) => s.length > 2);
317
+ expect(() => schema.validate("asdf")).toThrow(z.core.$ZodAsyncError);
318
+ await expect(schema.validateAsync("asdf")).resolves.toBe(true);
319
+ await expect(schema.validateAsync("a")).resolves.toBe(false);
320
+ await expect(z.string().validateAsync(12)).resolves.toBe(false);
321
+ });
322
+
323
+ test("zod/mini has no validate method", () => {
324
+ const schema = zm.string();
325
+ expect("parse" in schema).toBe(true);
326
+ expect("validate" in schema).toBe(false);
327
+ expect("validateAsync" in schema).toBe(false);
328
+ });
329
+
330
+ // counts reads of each child slot, so a stopped walk is observable without putting a callback in the schema — a refinement spy would work too, but reading the input says nothing about what ran
331
+ function counted(
332
+ slots: Record<string, unknown>,
333
+ bad: Record<string, unknown> = {}
334
+ ): [Record<string, unknown>, () => number] {
335
+ let reads = 0;
336
+ const obj: Record<string, unknown> = { ...bad };
337
+ for (const [k, v] of Object.entries(slots)) {
338
+ Object.defineProperty(obj, k, {
339
+ enumerable: true,
340
+ get() {
341
+ reads++;
342
+ return v;
343
+ },
344
+ });
345
+ }
346
+ return [obj, () => reads];
347
+ }
348
+
349
+ test("validate stops a container at its first aborting issue", () => {
350
+ const shape = { a: z.number(), b: z.string(), c: z.string() };
351
+
352
+ for (const jitless of [false, true]) {
353
+ const label = jitless ? "interpreted" : "compiled";
354
+ const [input, reads] = counted({ b: "x", c: "x" }, { a: "no" });
355
+ expect(z.validate(z.object(shape), input, { jitless }), label).toBe(false);
356
+ expect(reads(), `${label}: keys read after the first abort`).toBe(0);
357
+
358
+ const [ok, okReads] = counted({ b: "x", c: "x" }, { a: 1 });
359
+ expect(z.validate(z.object(shape), ok, { jitless }), label).toBe(true);
360
+ expect(okReads(), `${label}: a valid parse still reads every key`).toBe(2);
361
+ }
362
+
363
+ // an array stops at the first bad element
364
+ const arr: unknown[] = [1];
365
+ let elementReads = 0;
366
+ for (const i of [1, 2]) {
367
+ Object.defineProperty(arr, i, {
368
+ enumerable: true,
369
+ get() {
370
+ elementReads++;
371
+ return "x";
372
+ },
373
+ });
374
+ }
375
+ expect(z.validate(z.array(z.string()), arr)).toBe(false);
376
+ expect(elementReads, "elements read after the first abort").toBe(0);
377
+
378
+ // the shape phase's abort carries across into the catchall
379
+ const [co, coReads] = counted({ b: "x" }, { a: "no" });
380
+ expect(z.validate(z.object({ a: z.number() }).catchall(z.string()), co)).toBe(false);
381
+ expect(coReads(), "catchall keys read after the shape aborted").toBe(0);
382
+
383
+ // and a tuple's fixed items carry into its rest
384
+ const tup: unknown[] = ["no"];
385
+ let restReads = 0;
386
+ for (const i of [1, 2]) {
387
+ Object.defineProperty(tup, i, {
388
+ enumerable: true,
389
+ get() {
390
+ restReads++;
391
+ return "x";
392
+ },
393
+ });
394
+ }
395
+ expect(z.validate(z.tuple([z.number()], z.string()), tup)).toBe(false);
396
+ expect(restReads, "rest elements read after a fixed item aborted").toBe(0);
397
+ });
398
+
399
+ test("a default provider runs only when the key is absent", () => {
400
+ const boom = (): never => {
401
+ throw new RangeError("boom");
402
+ };
403
+ // the provider sits behind an accessor, so reading the def would call it
404
+ for (const [name, schema] of [
405
+ ["default", z.object({ a: z.number(), b: z.string().default(boom as any) })],
406
+ ["prefault", z.object({ a: z.number(), b: z.string().prefault(boom as any) })],
407
+ ] as const) {
408
+ expect(z.validate(schema, { a: "bad", b: "ok" }), name).toBe(false);
409
+ expect(z.validate(schema, { a: 1, b: "ok" }), name).toBe(true);
410
+ }
411
+ // absent, the provider does run, and its throw is the parse's own
412
+ expect(() => z.validate(z.object({ b: z.string().default(boom as any) }), {})).toThrow(RangeError);
413
+ });
414
+
415
+ test("the first failure stops the walk whatever follows it", () => {
416
+ // a sibling after the failure is never parsed, so its refinement never runs
417
+ let calls = 0;
418
+ const spy = z.string().refine(() => {
419
+ calls++;
420
+ return true;
421
+ });
422
+ expect(z.validate(z.object({ a: z.number(), b: spy, c: spy }), { a: "no", b: "x", c: "x" })).toBe(false);
423
+ expect(calls).toBe(0);
424
+
425
+ // reads of the trailing key say whether the walk stopped, without putting a callback in the schema
426
+ const skips = (b: z.ZodType, value: unknown = "x") => {
427
+ let reads = 0;
428
+ const input: Record<string, unknown> = { a: "no" };
429
+ Object.defineProperty(input, "b", {
430
+ enumerable: true,
431
+ get() {
432
+ reads++;
433
+ return value;
434
+ },
435
+ });
436
+ z.validate(z.object({ a: z.number(), b }), input);
437
+ return reads === 0;
438
+ };
439
+
440
+ // the trailing key is skipped no matter what it holds -- user code included, since it is never reached
441
+ for (const [name, b, value] of [
442
+ ["plain", z.string(), "x"],
443
+ ["min", z.string().min(2), "x"],
444
+ ["email", z.email(), "x"],
445
+ ["array", z.array(z.string().min(2)), ["ab"]],
446
+ ["error map", z.string({ error: () => "nope" }), "x"],
447
+ ["transform", z.string().transform((v) => v), "x"],
448
+ ["refine", z.string().refine(() => true), "x"],
449
+ ["custom", z.custom(() => true), "x"],
450
+ ["catch", z.string().catch("x"), "x"],
451
+ ["lazy", z.lazy(() => z.string()), "x"],
452
+ ["coerce", z.coerce.number(), 1],
453
+ ] as [string, z.ZodType, unknown][]) {
454
+ expect(skips(b, value), name).toBe(true);
455
+ }
456
+ });
457
+
458
+ test("a continuable issue never stops the walk", () => {
459
+ // .min() is continuable, so a surrounding schema can still reconcile it and the guard must not stop
460
+ let calls = 0;
461
+ const el = z
462
+ .string()
463
+ .min(5)
464
+ .refine(() => {
465
+ calls++;
466
+ return true;
467
+ });
468
+ expect(z.validate(z.array(el), ["a", "b", "c"])).toBe(false);
469
+ expect(calls).toBe(3);
470
+ });
471
+
472
+ test("z.record keeps walking under validate", () => {
473
+ // deliberate asymmetry: a record's invalid_key aborts, but an enclosing intersection reconciles it against the sibling operand, so a stopped loop hides keys the sibling does not own
474
+ let reads = 0;
475
+ const input: Record<string, unknown> = { a: 1 };
476
+ for (const k of ["b", "c"]) {
477
+ Object.defineProperty(input, k, {
478
+ enumerable: true,
479
+ get() {
480
+ reads++;
481
+ return "x";
482
+ },
483
+ });
484
+ }
485
+ expect(z.validate(z.record(z.string(), z.string()), input)).toBe(false);
486
+ expect(reads).toBe(2);
487
+ });
488
+
489
+ test("validate matches safeParse where an issue can still be reconciled away", async () => {
490
+ const recA = z.record(z.string().regex(/^a/), z.any());
491
+ const recB = z.record(z.string().regex(/^b/), z.any());
492
+ const schemas: z.ZodType[] = [
493
+ z.intersection(recA, recB),
494
+ z.intersection(recA.pipe(z.any()), recB.pipe(z.any())),
495
+ z.intersection(z.strictObject({ a: z.string() }), z.strictObject({ b: z.number() })),
496
+ z.intersection(z.array(z.string()), z.array(z.string().min(2))),
497
+ z.strictObject({ a: z.string() }).pipe(z.any()),
498
+ z.union([z.strictObject({ a: z.string() }), z.strictObject({ a: z.string(), b: z.number() })]),
499
+ z.array(z.string()).catch([]),
500
+ z.object({ a: z.string() }).optional(),
501
+ ];
502
+ const inputs: unknown[] = [
503
+ { a1: 1, b1: 2 },
504
+ { a1: 1, b1: 2, zz: 3 },
505
+ { a1: 1, zz: 2, b1: 3, yy: 4 },
506
+ { b1: 1, a1: 2, zz: 3, yy: 4 },
507
+ { a: "x", b: 1 },
508
+ { a: "x", b: 1, c: 9 },
509
+ { a: "x" },
510
+ ["ab", "cd"],
511
+ ["a", "b"],
512
+ undefined,
513
+ ];
514
+
515
+ const outcome = (fn: () => unknown) => {
516
+ try {
517
+ return `ok:${fn()}`;
518
+ } catch (err) {
519
+ return `throw:${(err as Error)?.constructor?.name}`;
520
+ }
521
+ };
522
+ const outcomeAsync = async (fn: () => Promise<unknown>) => {
523
+ try {
524
+ return `ok:${await fn()}`;
525
+ } catch (err) {
526
+ return `throw:${(err as Error)?.constructor?.name}`;
527
+ }
528
+ };
529
+
530
+ for (const schema of schemas) {
531
+ for (const input of inputs) {
532
+ const label = `${schema._zod.def.type} on ${JSON.stringify(input)}`;
533
+ expect(
534
+ outcome(() => z.validate(schema, input)),
535
+ label
536
+ ).toBe(outcome(() => schema.safeParse(input).success));
537
+ expect(await outcomeAsync(() => z.validateAsync(schema, input)), label).toBe(
538
+ await outcomeAsync(async () => (await schema.safeParseAsync(input)).success)
539
+ );
540
+ }
541
+ }
542
+ });
543
+
544
+ test("abortEarly does not leak into safeParse", () => {
545
+ const schema = z.object({ a: z.string(), b: z.string(), c: z.string() });
546
+ expect(schema.safeParse({ a: 1, b: 2, c: 3 }).error!.issues).toHaveLength(3);
547
+ expect(z.validate(schema, { a: 1, b: 2, c: 3 })).toBe(false);
548
+ expect(schema.safeParse({ a: 1, b: 2, c: 3 }).error!.issues).toHaveLength(3);
549
+ });
550
+
551
+ test("a callback after the first failure never runs, so validate answers where safeParse throws", () => {
552
+ const boom = (): never => {
553
+ throw new RangeError("boom");
554
+ };
555
+ // the deliberate divergence, in every shape that can carry a callback: an earlier sibling settles the boolean, so the later throw is never reached
556
+ const lateSym = Symbol("late");
557
+ const cases: [string, z.ZodType, unknown][] = [
558
+ ["object transform", z.object({ a: z.number(), b: z.string().transform(boom) }), { a: "bad", b: "ok" }],
559
+ ["object refine", z.object({ a: z.number(), b: z.string().refine(boom) }), { a: "bad", b: "ok" }],
560
+ ["object custom", z.object({ a: z.number(), b: z.custom(boom) }), { a: "bad", b: "ok" }],
561
+ // these three hang the callback off `_zod.check` rather than the def
562
+ ["object check", z.object({ a: z.number(), b: z.string().check(boom) }), { a: "bad", b: "ok" }],
563
+ ["object superRefine", z.object({ a: z.number(), b: z.string().superRefine(boom) }), { a: "bad", b: "ok" }],
564
+ ["object overwrite", z.object({ a: z.number(), b: z.string().overwrite(boom as any) }), { a: "bad", b: "ok" }],
565
+ // the input must carry the same symbol with a value the field accepts, or the transform never runs and the row asserts nothing
566
+ [
567
+ "symbol key",
568
+ z.object({ a: z.number(), [lateSym]: z.string().transform(boom) } as any),
569
+ { a: "bad", [lateSym]: "ok" },
570
+ ],
571
+ ["object catch", z.object({ a: z.number(), b: z.string().catch(boom) }), { a: "bad", b: 1 }],
572
+ ["object lazy", z.object({ a: z.number(), b: z.lazy(() => z.string().transform(boom)) }), { a: "bad", b: "ok" }],
573
+ ["array", z.array(z.union([z.number(), z.string().transform(boom)])), [true, "throws"]],
574
+ ["tuple rest", z.tuple([z.number()], z.string().transform(boom)), ["bad", "throws"]],
575
+ ["catchall", z.object({ a: z.number() }).catchall(z.string().transform(boom)), { a: "bad", b: "ok" }],
576
+ ["set", z.set(z.union([z.number(), z.string().transform(boom)])), new Set([true, "throws"])],
577
+ [
578
+ "map",
579
+ z.map(z.string(), z.union([z.number(), z.string().transform(boom)])),
580
+ new Map<any, any>([
581
+ [1, 0],
582
+ ["k", "throws"],
583
+ ]),
584
+ ],
585
+ ];
586
+
587
+ const outcome = (fn: () => unknown) => {
588
+ try {
589
+ return `ok:${fn()}`;
590
+ } catch (err) {
591
+ return `throw:${(err as Error)?.constructor?.name}`;
592
+ }
593
+ };
594
+
595
+ for (const [name, schema, input] of cases) {
596
+ // safeParse walks the whole tree and reaches the throw; validate settled the answer at the earlier sibling and never runs it
597
+ expect(
598
+ outcome(() => schema.safeParse(input).success),
599
+ `${name}: safeParse`
600
+ ).toBe("throw:RangeError");
601
+ expect(
602
+ outcome(() => z.validate(schema, input)),
603
+ `${name}: validate`
604
+ ).toBe("ok:false");
605
+ }
606
+ });
607
+
608
+ test("the stop lands between children, not inside one", () => {
609
+ const boom = (): never => {
610
+ throw new RangeError("boom");
611
+ };
612
+ // both parse as a unit, so an abort in one half cannot skip the other; stopping inside either risks a discarded issue turning a false into a true
613
+ const pairs: [string, z.ZodType, unknown][] = [
614
+ ["map entry", z.map(z.number(), z.string().transform(boom)), new Map([["bad", "ok"]])],
615
+ ["tuple fixed item", z.tuple([z.number(), z.string().transform(boom)]), ["bad", "ok"]],
616
+ ];
617
+ for (const [name, schema, input] of pairs) {
618
+ expect(() => z.validate(schema, input), name).toThrow(RangeError);
619
+ expect(() => schema.safeParse(input), `${name}: safeParse agrees`).toThrow(RangeError);
620
+ }
621
+
622
+ // between children, the stop does happen
623
+ expect(z.validate(z.object({ a: z.number(), b: z.string().transform(boom) }), { a: "bad", b: "ok" })).toBe(false);
624
+ expect(z.validate(z.array(z.union([z.number(), z.string().transform(boom)])), [true, "ok"])).toBe(false);
625
+ });
626
+
627
+ test("validate rethrows a callback it actually reaches", () => {
628
+ const boom = (): never => {
629
+ throw new RangeError("boom");
630
+ };
631
+ // nothing rejects before the callback, so validate reaches it and the throw is the caller's
632
+ const cases: [string, z.ZodType, unknown][] = [
633
+ ["transform", z.object({ a: z.string().transform(boom), b: z.number() }), { a: "ok", b: "bad" }],
634
+ ["refine", z.object({ a: z.string().refine(boom), b: z.number() }), { a: "ok", b: "bad" }],
635
+ ["check", z.object({ a: z.string().check(boom), b: z.number() }), { a: "ok", b: "bad" }],
636
+ ["array element", z.array(z.string().transform(boom)), ["ok", "ok"]],
637
+ ["catchall", z.object({}).catchall(z.string().transform(boom)), { a: "ok" }],
638
+ ["set", z.set(z.string().transform(boom)), new Set(["ok"])],
639
+ ["map", z.map(z.string(), z.string().transform(boom)), new Map([["k", "ok"]])],
640
+ ["tuple rest", z.tuple([z.string()], z.string().transform(boom)), ["ok", "ok"]],
641
+ ];
642
+ for (const [name, schema, input] of cases) {
643
+ expect(() => z.validate(schema, input), name).toThrow(RangeError);
644
+ }
645
+ });
@@ -498,6 +498,23 @@ export function _creditCard<T extends schemas.$ZodCreditCard>(
498
498
  });
499
499
  }
500
500
 
501
+ // IBAN
502
+ export type $ZodIBANParams = StringFormatParams<schemas.$ZodIBAN, "pattern" | "when">;
503
+ export type $ZodCheckIBANParams = CheckStringFormatParams<schemas.$ZodIBAN, "pattern" | "when">;
504
+ // @__NO_SIDE_EFFECTS__
505
+ export function _iban<T extends schemas.$ZodIBAN>(
506
+ Class: util.SchemaClass<T>,
507
+ params?: string | $ZodIBANParams | $ZodCheckIBANParams
508
+ ): T {
509
+ return new Class({
510
+ type: "string",
511
+ format: "iban",
512
+ check: "string_format",
513
+ abort: false,
514
+ ...util.normalizeParams(params),
515
+ });
516
+ }
517
+
501
518
  // JWT
502
519
  export type $ZodJWTParams = StringFormatParams<schemas.$ZodJWT, "pattern" | "when">;
503
520
  export type $ZodCheckJWTParams = CheckStringFormatParams<schemas.$ZodJWT, "pattern" | "when">;
@@ -1118,7 +1135,7 @@ export function _property<K extends string, T extends schemas.$ZodType>(
1118
1135
  property: K,
1119
1136
  schema: T,
1120
1137
  params?: string | $ZodCheckPropertyParams
1121
- ): checks.$ZodCheckProperty<{ [k in K]: core.output<T> }> {
1138
+ ): checks.$ZodCheckProperty<{ [k in K]: util.Widen<core.input<T>> }> {
1122
1139
  return new checks.$ZodCheckProperty({
1123
1140
  check: "property",
1124
1141
  property,
@@ -1127,13 +1144,20 @@ export function _property<K extends string, T extends schemas.$ZodType>(
1127
1144
  });
1128
1145
  }
1129
1146
 
1147
+ // `when` is omitted: it gates a check inside the run loop, so it means nothing when this is parsed as a schema, and honoring it in one role only would diverge silently
1148
+ export type $ZodPropertiesParams = CheckTypeParams<schemas.$ZodProperties, "shape" | "when">;
1130
1149
  // @__NO_SIDE_EFFECTS__
1131
1150
  export function _properties<Shape extends schemas.$ZodShape>(
1132
- shape: Shape
1133
- ): checks.$ZodCheckProperty<{ -readonly [k in keyof Shape]: core.output<Shape[k]> }>[] {
1134
- return Object.entries(shape).map(
1135
- ([property, schema]) => new checks.$ZodCheckProperty({ check: "property", property, schema })
1136
- ) as any;
1151
+ Class: util.SchemaClass<schemas.$ZodProperties>,
1152
+ shape: Shape,
1153
+ params?: string | $ZodPropertiesParams
1154
+ ): schemas.$ZodProperties<Shape> {
1155
+ return new Class({
1156
+ type: "properties",
1157
+ check: "properties",
1158
+ shape,
1159
+ ...util.normalizeParams(params),
1160
+ }) as any;
1137
1161
  }
1138
1162
 
1139
1163
  export type $ZodCheckMimeTypeParams = CheckParams<checks.$ZodCheckMimeType, "mime" | "when">;