zod 4.2.0-canary.20251021T174027 → 4.2.0-canary.20251106T212241

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod",
3
- "version": "4.2.0-canary.20251021T174027",
3
+ "version": "4.2.0-canary.20251106T212241",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Colin McDonnell <zod@colinhacks.com>",
@@ -354,3 +354,44 @@ test("partial record", () => {
354
354
 
355
355
  expect(Person.def.keyType._zod.def.type).toEqual("enum");
356
356
  });
357
+
358
+ test("partialRecord with z.literal([key, ...])", () => {
359
+ const Keys = z.literal(["id", "name", "email"]);
360
+ const schema = z.partialRecord(Keys, z.string());
361
+ type Schema = z.infer<typeof schema>;
362
+ expectTypeOf<Schema>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
363
+
364
+ // Should parse valid partials
365
+ expect(schema.parse({})).toEqual({});
366
+ expect(schema.parse({ id: "1" })).toEqual({ id: "1" });
367
+ expect(schema.parse({ name: "n", email: "e@example.com" })).toEqual({ name: "n", email: "e@example.com" });
368
+
369
+ // Should fail with unrecognized key, error checked via inline snapshot
370
+ expect(schema.safeParse({ foo: "bar" })).toMatchInlineSnapshot(`
371
+ {
372
+ "error": [ZodError: [
373
+ {
374
+ "code": "invalid_key",
375
+ "origin": "record",
376
+ "issues": [
377
+ {
378
+ "code": "invalid_value",
379
+ "values": [
380
+ "id",
381
+ "name",
382
+ "email"
383
+ ],
384
+ "path": [],
385
+ "message": "Invalid option: expected one of \\"id\\"|\\"name\\"|\\"email\\""
386
+ }
387
+ ],
388
+ "path": [
389
+ "foo"
390
+ ],
391
+ "message": "Invalid key in record"
392
+ }
393
+ ]],
394
+ "success": false,
395
+ }
396
+ `);
397
+ });
@@ -1783,7 +1783,7 @@ function handleCatchall(
1783
1783
  const keySet = def.keySet;
1784
1784
  const _catchall = def.catchall!._zod;
1785
1785
  const t = _catchall.def.type;
1786
- for (const key of Object.keys(input)) {
1786
+ for (const key in input) {
1787
1787
  if (keySet.has(key)) continue;
1788
1788
  if (t === "never") {
1789
1789
  unrecognized.push(key);
@@ -2933,7 +2933,8 @@ export const $ZodLiteral: core.$constructor<$ZodLiteral> = /*@__PURE__*/ core.$c
2933
2933
  throw new Error("Cannot create literal schema with no valid values");
2934
2934
  }
2935
2935
 
2936
- inst._zod.values = new Set<util.Literal>(def.values);
2936
+ const values = new Set<util.Literal>(def.values);
2937
+ inst._zod.values = values;
2937
2938
  inst._zod.pattern = new RegExp(
2938
2939
  `^(${def.values
2939
2940
 
@@ -2943,7 +2944,7 @@ export const $ZodLiteral: core.$constructor<$ZodLiteral> = /*@__PURE__*/ core.$c
2943
2944
 
2944
2945
  inst._zod.parse = (payload, _ctx) => {
2945
2946
  const input = payload.value;
2946
- if (inst._zod.values.has(input)) {
2947
+ if (values.has(input)) {
2947
2948
  return payload;
2948
2949
  }
2949
2950
  payload.issues.push({
@@ -947,98 +947,55 @@ function isTransforming(
947
947
  if (ctx.seen.has(_schema)) return false;
948
948
  ctx.seen.add(_schema);
949
949
 
950
- const schema = _schema as schemas.$ZodTypes;
951
- const def = schema._zod.def;
952
- switch (def.type) {
953
- case "string":
954
- case "number":
955
- case "bigint":
956
- case "boolean":
957
- case "date":
958
- case "symbol":
959
- case "undefined":
960
- case "null":
961
- case "any":
962
- case "unknown":
963
- case "never":
964
- case "void":
965
- case "literal":
966
- case "enum":
967
- case "nan":
968
- case "file":
969
- case "template_literal":
970
- return false;
971
- case "array": {
972
- return isTransforming(def.element, ctx);
973
- }
974
- case "object": {
975
- for (const key in def.shape) {
976
- if (isTransforming(def.shape[key]!, ctx)) return true;
977
- }
978
- return false;
979
- }
980
- case "union": {
981
- for (const option of def.options) {
982
- if (isTransforming(option, ctx)) return true;
983
- }
984
- return false;
985
- }
986
- case "intersection": {
987
- return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
988
- }
989
- case "tuple": {
990
- for (const item of def.items) {
991
- if (isTransforming(item, ctx)) return true;
992
- }
993
- if (def.rest && isTransforming(def.rest, ctx)) return true;
994
- return false;
995
- }
996
- case "record": {
997
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
998
- }
999
- case "map": {
1000
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
1001
- }
1002
- case "set": {
1003
- return isTransforming(def.valueType, ctx);
1004
- }
950
+ const def = (_schema as schemas.$ZodTypes)._zod.def;
951
+
952
+ if (def.type === "transform") return true;
953
+
954
+ if (def.type === "array") return isTransforming(def.element, ctx);
955
+ if (def.type === "set") return isTransforming(def.valueType, ctx);
956
+ if (def.type === "lazy") return isTransforming(def.getter(), ctx);
957
+
958
+ if (
959
+ def.type === "promise" ||
960
+ def.type === "optional" ||
961
+ def.type === "nonoptional" ||
962
+ def.type === "nullable" ||
963
+ def.type === "readonly" ||
964
+ def.type === "default" ||
965
+ def.type === "prefault"
966
+ ) {
967
+ return isTransforming(def.innerType, ctx);
968
+ }
1005
969
 
1006
- // inner types
1007
- case "promise":
1008
- case "optional":
1009
- case "nonoptional":
1010
- case "nullable":
1011
- case "readonly":
1012
- return isTransforming(def.innerType, ctx);
1013
- case "lazy":
1014
- return isTransforming(def.getter(), ctx);
1015
- case "default": {
1016
- return isTransforming(def.innerType, ctx);
1017
- }
1018
- case "prefault": {
1019
- return isTransforming(def.innerType, ctx);
1020
- }
1021
- case "custom": {
1022
- return false;
1023
- }
1024
- case "transform": {
1025
- return true;
1026
- }
1027
- case "pipe": {
1028
- return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
1029
- }
1030
- case "success": {
1031
- return false;
970
+ if (def.type === "intersection") {
971
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
972
+ }
973
+ if (def.type === "record" || def.type === "map") {
974
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
975
+ }
976
+ if (def.type === "pipe") {
977
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
978
+ }
979
+
980
+ if (def.type === "object") {
981
+ for (const key in def.shape) {
982
+ if (isTransforming(def.shape[key]!, ctx)) return true;
1032
983
  }
1033
- case "catch": {
1034
- return false;
984
+ return false;
985
+ }
986
+ if (def.type === "union") {
987
+ for (const option of def.options) {
988
+ if (isTransforming(option, ctx)) return true;
1035
989
  }
1036
- case "function": {
1037
- return false;
990
+ return false;
991
+ }
992
+ if (def.type === "tuple") {
993
+ for (const item of def.items) {
994
+ if (isTransforming(item, ctx)) return true;
1038
995
  }
1039
-
1040
- default:
1041
- def satisfies never;
996
+ if (def.rest && isTransforming(def.rest, ctx)) return true;
997
+ return false;
1042
998
  }
1043
- throw new Error(`Unknown schema type: ${(def as any).type}`);
999
+
1000
+ return false;
1044
1001
  }
@@ -758,7 +758,7 @@ function handleCatchall(proms, input, payload, ctx, def, inst) {
758
758
  const keySet = def.keySet;
759
759
  const _catchall = def.catchall._zod;
760
760
  const t = _catchall.def.type;
761
- for (const key of Object.keys(input)) {
761
+ for (const key in input) {
762
762
  if (keySet.has(key))
763
763
  continue;
764
764
  if (t === "never") {
@@ -1439,13 +1439,14 @@ exports.$ZodLiteral = core.$constructor("$ZodLiteral", (inst, def) => {
1439
1439
  if (def.values.length === 0) {
1440
1440
  throw new Error("Cannot create literal schema with no valid values");
1441
1441
  }
1442
- inst._zod.values = new Set(def.values);
1442
+ const values = new Set(def.values);
1443
+ inst._zod.values = values;
1443
1444
  inst._zod.pattern = new RegExp(`^(${def.values
1444
1445
  .map((o) => (typeof o === "string" ? util.escapeRegex(o) : o ? util.escapeRegex(o.toString()) : String(o)))
1445
1446
  .join("|")})$`);
1446
1447
  inst._zod.parse = (payload, _ctx) => {
1447
1448
  const input = payload.value;
1448
- if (inst._zod.values.has(input)) {
1449
+ if (values.has(input)) {
1449
1450
  return payload;
1450
1451
  }
1451
1452
  payload.issues.push({
@@ -727,7 +727,7 @@ function handleCatchall(proms, input, payload, ctx, def, inst) {
727
727
  const keySet = def.keySet;
728
728
  const _catchall = def.catchall._zod;
729
729
  const t = _catchall.def.type;
730
- for (const key of Object.keys(input)) {
730
+ for (const key in input) {
731
731
  if (keySet.has(key))
732
732
  continue;
733
733
  if (t === "never") {
@@ -1408,13 +1408,14 @@ export const $ZodLiteral = /*@__PURE__*/ core.$constructor("$ZodLiteral", (inst,
1408
1408
  if (def.values.length === 0) {
1409
1409
  throw new Error("Cannot create literal schema with no valid values");
1410
1410
  }
1411
- inst._zod.values = new Set(def.values);
1411
+ const values = new Set(def.values);
1412
+ inst._zod.values = values;
1412
1413
  inst._zod.pattern = new RegExp(`^(${def.values
1413
1414
  .map((o) => (typeof o === "string" ? util.escapeRegex(o) : o ? util.escapeRegex(o.toString()) : String(o)))
1414
1415
  .join("|")})$`);
1415
1416
  inst._zod.parse = (payload, _ctx) => {
1416
1417
  const input = payload.value;
1417
- if (inst._zod.values.has(input)) {
1418
+ if (values.has(input)) {
1418
1419
  return payload;
1419
1420
  }
1420
1421
  payload.issues.push({
@@ -821,100 +821,55 @@ function isTransforming(_schema, _ctx) {
821
821
  if (ctx.seen.has(_schema))
822
822
  return false;
823
823
  ctx.seen.add(_schema);
824
- const schema = _schema;
825
- const def = schema._zod.def;
826
- switch (def.type) {
827
- case "string":
828
- case "number":
829
- case "bigint":
830
- case "boolean":
831
- case "date":
832
- case "symbol":
833
- case "undefined":
834
- case "null":
835
- case "any":
836
- case "unknown":
837
- case "never":
838
- case "void":
839
- case "literal":
840
- case "enum":
841
- case "nan":
842
- case "file":
843
- case "template_literal":
844
- return false;
845
- case "array": {
846
- return isTransforming(def.element, ctx);
847
- }
848
- case "object": {
849
- for (const key in def.shape) {
850
- if (isTransforming(def.shape[key], ctx))
851
- return true;
852
- }
853
- return false;
854
- }
855
- case "union": {
856
- for (const option of def.options) {
857
- if (isTransforming(option, ctx))
858
- return true;
859
- }
860
- return false;
861
- }
862
- case "intersection": {
863
- return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
864
- }
865
- case "tuple": {
866
- for (const item of def.items) {
867
- if (isTransforming(item, ctx))
868
- return true;
869
- }
870
- if (def.rest && isTransforming(def.rest, ctx))
824
+ const def = _schema._zod.def;
825
+ if (def.type === "transform")
826
+ return true;
827
+ if (def.type === "array")
828
+ return isTransforming(def.element, ctx);
829
+ if (def.type === "set")
830
+ return isTransforming(def.valueType, ctx);
831
+ if (def.type === "lazy")
832
+ return isTransforming(def.getter(), ctx);
833
+ if (def.type === "promise" ||
834
+ def.type === "optional" ||
835
+ def.type === "nonoptional" ||
836
+ def.type === "nullable" ||
837
+ def.type === "readonly" ||
838
+ def.type === "default" ||
839
+ def.type === "prefault") {
840
+ return isTransforming(def.innerType, ctx);
841
+ }
842
+ if (def.type === "intersection") {
843
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
844
+ }
845
+ if (def.type === "record" || def.type === "map") {
846
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
847
+ }
848
+ if (def.type === "pipe") {
849
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
850
+ }
851
+ if (def.type === "object") {
852
+ for (const key in def.shape) {
853
+ if (isTransforming(def.shape[key], ctx))
871
854
  return true;
872
- return false;
873
- }
874
- case "record": {
875
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
876
- }
877
- case "map": {
878
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
879
- }
880
- case "set": {
881
- return isTransforming(def.valueType, ctx);
882
855
  }
883
- // inner types
884
- case "promise":
885
- case "optional":
886
- case "nonoptional":
887
- case "nullable":
888
- case "readonly":
889
- return isTransforming(def.innerType, ctx);
890
- case "lazy":
891
- return isTransforming(def.getter(), ctx);
892
- case "default": {
893
- return isTransforming(def.innerType, ctx);
894
- }
895
- case "prefault": {
896
- return isTransforming(def.innerType, ctx);
856
+ return false;
857
+ }
858
+ if (def.type === "union") {
859
+ for (const option of def.options) {
860
+ if (isTransforming(option, ctx))
861
+ return true;
897
862
  }
898
- case "custom": {
899
- return false;
863
+ return false;
864
+ }
865
+ if (def.type === "tuple") {
866
+ for (const item of def.items) {
867
+ if (isTransforming(item, ctx))
868
+ return true;
900
869
  }
901
- case "transform": {
870
+ if (def.rest && isTransforming(def.rest, ctx))
902
871
  return true;
903
- }
904
- case "pipe": {
905
- return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
906
- }
907
- case "success": {
908
- return false;
909
- }
910
- case "catch": {
911
- return false;
912
- }
913
- case "function": {
914
- return false;
915
- }
916
- default:
917
- def;
872
+ return false;
918
873
  }
919
- throw new Error(`Unknown schema type: ${def.type}`);
874
+ return false;
920
875
  }
@@ -816,100 +816,55 @@ function isTransforming(_schema, _ctx) {
816
816
  if (ctx.seen.has(_schema))
817
817
  return false;
818
818
  ctx.seen.add(_schema);
819
- const schema = _schema;
820
- const def = schema._zod.def;
821
- switch (def.type) {
822
- case "string":
823
- case "number":
824
- case "bigint":
825
- case "boolean":
826
- case "date":
827
- case "symbol":
828
- case "undefined":
829
- case "null":
830
- case "any":
831
- case "unknown":
832
- case "never":
833
- case "void":
834
- case "literal":
835
- case "enum":
836
- case "nan":
837
- case "file":
838
- case "template_literal":
839
- return false;
840
- case "array": {
841
- return isTransforming(def.element, ctx);
842
- }
843
- case "object": {
844
- for (const key in def.shape) {
845
- if (isTransforming(def.shape[key], ctx))
846
- return true;
847
- }
848
- return false;
849
- }
850
- case "union": {
851
- for (const option of def.options) {
852
- if (isTransforming(option, ctx))
853
- return true;
854
- }
855
- return false;
856
- }
857
- case "intersection": {
858
- return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
859
- }
860
- case "tuple": {
861
- for (const item of def.items) {
862
- if (isTransforming(item, ctx))
863
- return true;
864
- }
865
- if (def.rest && isTransforming(def.rest, ctx))
819
+ const def = _schema._zod.def;
820
+ if (def.type === "transform")
821
+ return true;
822
+ if (def.type === "array")
823
+ return isTransforming(def.element, ctx);
824
+ if (def.type === "set")
825
+ return isTransforming(def.valueType, ctx);
826
+ if (def.type === "lazy")
827
+ return isTransforming(def.getter(), ctx);
828
+ if (def.type === "promise" ||
829
+ def.type === "optional" ||
830
+ def.type === "nonoptional" ||
831
+ def.type === "nullable" ||
832
+ def.type === "readonly" ||
833
+ def.type === "default" ||
834
+ def.type === "prefault") {
835
+ return isTransforming(def.innerType, ctx);
836
+ }
837
+ if (def.type === "intersection") {
838
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
839
+ }
840
+ if (def.type === "record" || def.type === "map") {
841
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
842
+ }
843
+ if (def.type === "pipe") {
844
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
845
+ }
846
+ if (def.type === "object") {
847
+ for (const key in def.shape) {
848
+ if (isTransforming(def.shape[key], ctx))
866
849
  return true;
867
- return false;
868
- }
869
- case "record": {
870
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
871
- }
872
- case "map": {
873
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
874
- }
875
- case "set": {
876
- return isTransforming(def.valueType, ctx);
877
850
  }
878
- // inner types
879
- case "promise":
880
- case "optional":
881
- case "nonoptional":
882
- case "nullable":
883
- case "readonly":
884
- return isTransforming(def.innerType, ctx);
885
- case "lazy":
886
- return isTransforming(def.getter(), ctx);
887
- case "default": {
888
- return isTransforming(def.innerType, ctx);
889
- }
890
- case "prefault": {
891
- return isTransforming(def.innerType, ctx);
851
+ return false;
852
+ }
853
+ if (def.type === "union") {
854
+ for (const option of def.options) {
855
+ if (isTransforming(option, ctx))
856
+ return true;
892
857
  }
893
- case "custom": {
894
- return false;
858
+ return false;
859
+ }
860
+ if (def.type === "tuple") {
861
+ for (const item of def.items) {
862
+ if (isTransforming(item, ctx))
863
+ return true;
895
864
  }
896
- case "transform": {
865
+ if (def.rest && isTransforming(def.rest, ctx))
897
866
  return true;
898
- }
899
- case "pipe": {
900
- return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
901
- }
902
- case "success": {
903
- return false;
904
- }
905
- case "catch": {
906
- return false;
907
- }
908
- case "function": {
909
- return false;
910
- }
911
- default:
912
- def;
867
+ return false;
913
868
  }
914
- throw new Error(`Unknown schema type: ${def.type}`);
869
+ return false;
915
870
  }