zod 3.26.0-canary.20250703T214020 → 3.26.0-canary.20250707T201657

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/index.cjs CHANGED
@@ -27,7 +27,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.z = void 0;
30
- const z = __importStar(require("./v3/index.cjs"));
30
+ const z = __importStar(require("./v3/external.cjs"));
31
31
  exports.z = z;
32
- __exportStar(require("./v3/index.cjs"), exports);
32
+ __exportStar(require("./v3/external.cjs"), exports);
33
33
  exports.default = z;
package/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import * as z from "./v3/index.cjs";
2
- export * from "./v3/index.cjs";
1
+ import * as z from "./v3/external.cjs";
2
+ export * from "./v3/external.cjs";
3
3
  export { z };
4
4
  export default z;
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as z from "./v3/index.js";
2
- export * from "./v3/index.js";
1
+ import * as z from "./v3/external.js";
2
+ export * from "./v3/external.js";
3
3
  export { z };
4
4
  export default z;
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as z from "./v3/index.js";
2
- export * from "./v3/index.js";
1
+ import * as z from "./v3/external.js";
2
+ export * from "./v3/external.js";
3
3
  export { z };
4
4
  export default z;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod",
3
- "version": "3.26.0-canary.20250703T214020",
3
+ "version": "3.26.0-canary.20250707T201657",
4
4
  "type": "module",
5
5
  "author": "Colin McDonnell <zod@colinhacks.com>",
6
6
  "description": "TypeScript-first schema declaration and validation library with static type inference",
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as z from "./v3/index.js";
2
- export * from "./v3/index.js";
1
+ import * as z from "./v3/external.js";
2
+ export * from "./v3/external.js";
3
3
  export { z };
4
4
  export default z;
@@ -365,6 +365,8 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
365
365
  inst.duration = (params) => inst.check(iso.duration(params as any));
366
366
  });
367
367
 
368
+ export function string(params?: string | core.$ZodStringParams): ZodString;
369
+ export function string<T extends string>(params?: string | core.$ZodStringParams): core.$ZodType<T, T>;
368
370
  export function string(params?: string | core.$ZodStringParams): ZodString {
369
371
  return core._string(ZodString, params) as any;
370
372
  }
@@ -1357,11 +1359,11 @@ export function partialRecord<Key extends core.$ZodRecordKey, Value extends core
1357
1359
  keyType: Key,
1358
1360
  valueType: Value,
1359
1361
  params?: string | core.$ZodRecordParams
1360
- ): ZodRecord<ZodUnion<[Key, ZodNever]>, Value> {
1362
+ ): ZodRecord<Key & core.$partial, Value> {
1361
1363
  return new ZodRecord({
1362
1364
  type: "record",
1363
1365
  keyType: union([keyType, never()]),
1364
- valueType: valueType as any as core.$ZodType,
1366
+ valueType: valueType as any,
1365
1367
  ...util.normalizeParams(params),
1366
1368
  }) as any;
1367
1369
  }
@@ -59,7 +59,5 @@ test("$branded", () => {
59
59
  test("branded record", () => {
60
60
  const recordWithBrandedNumberKeys = z.record(z.string().brand("SomeBrand"), z.number());
61
61
  type recordWithBrandedNumberKeys = z.infer<typeof recordWithBrandedNumberKeys>;
62
- expectTypeOf<recordWithBrandedNumberKeys>().toEqualTypeOf<
63
- Record<string & z.core.$brand<"SomeBrand">, number | undefined>
64
- >();
62
+ expectTypeOf<recordWithBrandedNumberKeys>().toEqualTypeOf<Record<string & z.core.$brand<"SomeBrand">, number>>();
65
63
  });
@@ -24,6 +24,9 @@ test("_values", () => {
24
24
 
25
25
  const post = z.literal("test").transform((_) => Math.random());
26
26
  expect(post._zod.values).toEqual(new Set(["test"]));
27
+
28
+ // Test that readonly literals pass through their values property
29
+ expect(z.literal("test").readonly()._zod.values).toEqual(new Set(["test"]));
27
30
  });
28
31
 
29
32
  test("valid parse - object", () => {
@@ -590,3 +593,27 @@ test("nested discriminated unions", () => {
590
593
  }
591
594
  `);
592
595
  });
596
+
597
+ test("readonly literal discriminator", () => {
598
+ const discUnion = z.discriminatedUnion("type", [
599
+ z.object({ type: z.literal("a").readonly(), a: z.string() }),
600
+ z.object({ type: z.literal("b"), b: z.number() }),
601
+ ]);
602
+
603
+ // Test that both discriminator values are correctly included in propValues
604
+ const propValues = discUnion._zod.propValues;
605
+ expect(propValues?.type?.has("a")).toBe(true);
606
+ expect(propValues?.type?.has("b")).toBe(true);
607
+
608
+ // Test that the discriminated union works correctly
609
+ const result1 = discUnion.parse({ type: "a", a: "hello" });
610
+ expect(result1).toEqual({ type: "a", a: "hello" });
611
+
612
+ const result2 = discUnion.parse({ type: "b", b: 42 });
613
+ expect(result2).toEqual({ type: "b", b: 42 });
614
+
615
+ // Test that invalid discriminator values are rejected
616
+ expect(() => {
617
+ discUnion.parse({ type: "c", a: "hello" });
618
+ }).toThrow();
619
+ });
@@ -301,7 +301,7 @@ test("z.record", () => {
301
301
  // partial enum
302
302
  const d = z.record(z.enum(["a", "b"]).or(z.never()), z.string());
303
303
  type d = z.output<typeof d>;
304
- expectTypeOf<d>().toEqualTypeOf<Partial<Record<"a" | "b", string>>>();
304
+ expectTypeOf<d>().toEqualTypeOf<Record<"a" | "b", string>>();
305
305
  });
306
306
 
307
307
  test("z.map", () => {
@@ -217,6 +217,16 @@ test("test inferred merged type", async () => {
217
217
  expectTypeOf<asdf>().toEqualTypeOf<{ a: number }>();
218
218
  });
219
219
 
220
+ test("inferred type with Record shape", () => {
221
+ type A = z.ZodObject<Record<string, z.ZodType<string, number>>>;
222
+ expectTypeOf<z.infer<A>>().toEqualTypeOf<Record<string, string>>();
223
+ expectTypeOf<z.input<A>>().toEqualTypeOf<Record<string, number>>();
224
+
225
+ type B = z.ZodObject;
226
+ expectTypeOf<z.infer<B>>().toEqualTypeOf<Record<string, unknown>>();
227
+ expectTypeOf<z.input<B>>().toEqualTypeOf<Record<string, unknown>>();
228
+ });
229
+
220
230
  test("inferred merged object type with optional properties", async () => {
221
231
  const Merged = z
222
232
  .object({ a: z.string(), b: z.string().optional() })
@@ -549,5 +559,5 @@ test("index signature in shape", () => {
549
559
  const schema = makeZodObj("foo");
550
560
  type schema = z.infer<typeof schema>;
551
561
 
552
- expectTypeOf<schema>().toEqualTypeOf<Record<string, unknown>>();
562
+ expectTypeOf<schema>().toEqualTypeOf<Record<string, string>>();
553
563
  });
@@ -37,6 +37,26 @@ test("optionality", () => {
37
37
  const e = z.string().default("asdf").nullable();
38
38
  expect(e._zod.optin).toEqual("optional");
39
39
  expect(e._zod.optout).toEqual(undefined);
40
+
41
+ // z.undefined should NOT be optional
42
+ const f = z.undefined();
43
+ expect(f._zod.optin).toEqual("optional");
44
+ expect(f._zod.optout).toEqual("optional");
45
+ expectTypeOf<typeof f._zod.optin>().toEqualTypeOf<"optional" | undefined>();
46
+ expectTypeOf<typeof f._zod.optout>().toEqualTypeOf<"optional" | undefined>();
47
+
48
+ // z.union should be optional if any of the types are optional
49
+ const g = z.union([z.string(), z.undefined()]);
50
+ expect(g._zod.optin).toEqual("optional");
51
+ expect(g._zod.optout).toEqual("optional");
52
+ expectTypeOf<typeof g._zod.optin>().toEqualTypeOf<"optional" | undefined>();
53
+ expectTypeOf<typeof g._zod.optout>().toEqualTypeOf<"optional" | undefined>();
54
+
55
+ const h = z.union([z.string(), z.optional(z.string())]);
56
+ expect(h._zod.optin).toEqual("optional");
57
+ expect(h._zod.optout).toEqual("optional");
58
+ expectTypeOf<typeof h._zod.optin>().toEqualTypeOf<"optional">();
59
+ expectTypeOf<typeof h._zod.optout>().toEqualTypeOf<"optional">();
40
60
  });
41
61
 
42
62
  test("pipe optionality", () => {
@@ -17,7 +17,7 @@ test("type inference", () => {
17
17
  expectTypeOf<booleanRecord>().toEqualTypeOf<Record<string, boolean>>();
18
18
  expectTypeOf<recordWithEnumKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
19
19
  expectTypeOf<recordWithLiteralKey>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
20
- expectTypeOf<recordWithLiteralUnionKeys>().toEqualTypeOf<Partial<Record<"Tuna" | "Salmon", string>>>();
20
+ expectTypeOf<recordWithLiteralUnionKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
21
21
  });
22
22
 
23
23
  test("enum exhaustiveness", () => {
@@ -330,3 +330,13 @@ test("async parsing", async () => {
330
330
  ]]
331
331
  `);
332
332
  });
333
+
334
+ test("partial record", () => {
335
+ const schema = z.partialRecord(z.string(), z.string());
336
+ type schema = z.infer<typeof schema>;
337
+ expectTypeOf<schema>().toEqualTypeOf<Partial<Record<string, string>>>();
338
+
339
+ const Keys = z.enum(["id", "name", "email"]).or(z.never());
340
+ const Person = z.partialRecord(Keys, z.string());
341
+ expectTypeOf<z.infer<typeof Person>>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
342
+ });
@@ -160,9 +160,10 @@ test("deferred self-recursion", () => {
160
160
  const Output = z.object({
161
161
  id: z.int(), //.nonnegative(),
162
162
  name: z.string(),
163
- features: z.array(Feature), //.array(), // <—
163
+ get features(): z.ZodArray<typeof Feature> {
164
+ return Feature.array();
165
+ },
164
166
  });
165
-
166
167
  type Output = z.output<typeof Output>;
167
168
 
168
169
  type _Feature = {
@@ -28,10 +28,9 @@ describe("toJSONSchema", () => {
28
28
  "type": "null",
29
29
  }
30
30
  `);
31
- expect(z.toJSONSchema(z.undefined())).toMatchInlineSnapshot(`
31
+ expect(z.toJSONSchema(z.undefined(), { unrepresentable: "any" })).toMatchInlineSnapshot(`
32
32
  {
33
33
  "$schema": "https://json-schema.org/draft/2020-12/schema",
34
- "type": "null",
35
34
  }
36
35
  `);
37
36
  expect(z.toJSONSchema(z.any())).toMatchInlineSnapshot(`
@@ -232,6 +231,7 @@ describe("toJSONSchema", () => {
232
231
  expect(() => z.toJSONSchema(z.int64())).toThrow("BigInt cannot be represented in JSON Schema");
233
232
  expect(() => z.toJSONSchema(z.symbol())).toThrow("Symbols cannot be represented in JSON Schema");
234
233
  expect(() => z.toJSONSchema(z.void())).toThrow("Void cannot be represented in JSON Schema");
234
+ expect(() => z.toJSONSchema(z.undefined())).toThrow("Undefined cannot be represented in JSON Schema");
235
235
  expect(() => z.toJSONSchema(z.date())).toThrow("Date cannot be represented in JSON Schema");
236
236
  expect(() => z.toJSONSchema(z.map(z.string(), z.number()))).toThrow("Map cannot be represented in JSON Schema");
237
237
  expect(() => z.toJSONSchema(z.set(z.string()))).toThrow("Set cannot be represented in JSON Schema");
@@ -1259,6 +1259,35 @@ test("override execution order", () => {
1259
1259
  `);
1260
1260
  });
1261
1261
 
1262
+ test("override with path", () => {
1263
+ const userSchema = z.object({
1264
+ name: z.string(),
1265
+ age: z.number(),
1266
+ });
1267
+
1268
+ const capturedPaths: (string | number)[][] = [];
1269
+
1270
+ z.toJSONSchema(userSchema, {
1271
+ override(ctx) {
1272
+ capturedPaths.push(ctx.path);
1273
+ },
1274
+ });
1275
+
1276
+ expect(capturedPaths).toMatchInlineSnapshot(`
1277
+ [
1278
+ [
1279
+ "properties",
1280
+ "age",
1281
+ ],
1282
+ [
1283
+ "properties",
1284
+ "name",
1285
+ ],
1286
+ [],
1287
+ ]
1288
+ `);
1289
+ });
1290
+
1262
1291
  test("pipe", () => {
1263
1292
  const mySchema = z
1264
1293
  .string()
@@ -1856,6 +1885,10 @@ test("input type", () => {
1856
1885
  c: z.string().default("hello"),
1857
1886
  d: z.string().nullable(),
1858
1887
  e: z.string().prefault("hello"),
1888
+ f: z.string().catch("hello"),
1889
+ g: z.never(),
1890
+ h: z.union([z.string(), z.number().default(2)]),
1891
+ i: z.union([z.string(), z.string().optional()]),
1859
1892
  });
1860
1893
  expect(z.toJSONSchema(schema, { io: "input" })).toMatchInlineSnapshot(`
1861
1894
  {
@@ -1885,10 +1918,39 @@ test("input type", () => {
1885
1918
  "default": "hello",
1886
1919
  "type": "string",
1887
1920
  },
1921
+ "f": {
1922
+ "default": "hello",
1923
+ "type": "string",
1924
+ },
1925
+ "g": {
1926
+ "not": {},
1927
+ },
1928
+ "h": {
1929
+ "anyOf": [
1930
+ {
1931
+ "type": "string",
1932
+ },
1933
+ {
1934
+ "default": 2,
1935
+ "type": "number",
1936
+ },
1937
+ ],
1938
+ },
1939
+ "i": {
1940
+ "anyOf": [
1941
+ {
1942
+ "type": "string",
1943
+ },
1944
+ {
1945
+ "type": "string",
1946
+ },
1947
+ ],
1948
+ },
1888
1949
  },
1889
1950
  "required": [
1890
1951
  "a",
1891
1952
  "d",
1953
+ "g",
1892
1954
  ],
1893
1955
  "type": "object",
1894
1956
  }
@@ -1921,12 +1983,43 @@ test("input type", () => {
1921
1983
  "e": {
1922
1984
  "type": "string",
1923
1985
  },
1986
+ "f": {
1987
+ "default": "hello",
1988
+ "type": "string",
1989
+ },
1990
+ "g": {
1991
+ "not": {},
1992
+ },
1993
+ "h": {
1994
+ "anyOf": [
1995
+ {
1996
+ "type": "string",
1997
+ },
1998
+ {
1999
+ "default": 2,
2000
+ "type": "number",
2001
+ },
2002
+ ],
2003
+ },
2004
+ "i": {
2005
+ "anyOf": [
2006
+ {
2007
+ "type": "string",
2008
+ },
2009
+ {
2010
+ "type": "string",
2011
+ },
2012
+ ],
2013
+ },
1924
2014
  },
1925
2015
  "required": [
1926
2016
  "a",
1927
2017
  "c",
1928
2018
  "d",
1929
2019
  "e",
2020
+ "f",
2021
+ "g",
2022
+ "h",
1930
2023
  ],
1931
2024
  "type": "object",
1932
2025
  }
@@ -46,6 +46,10 @@ export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema exten
46
46
  }
47
47
 
48
48
  remove(schema: Schema): this {
49
+ const meta: any = this._map.get(schema);
50
+ if (meta && typeof meta === "object" && "id" in meta) {
51
+ this._idmap.delete(meta.id!);
52
+ }
49
53
  this._map.delete(schema);
50
54
  return this;
51
55
  }