import { expect, expectTypeOf, test } from "vitest"; import * as z from "zod/v4"; test("type inference", () => { const booleanRecord = z.record(z.string(), z.boolean()); type booleanRecord = typeof booleanRecord._output; const recordWithEnumKeys = z.record(z.enum(["Tuna", "Salmon"]), z.string()); type recordWithEnumKeys = z.infer; const recordWithLiteralKey = z.record(z.literal(["Tuna", "Salmon", 21]), z.string()); type recordWithLiteralKey = z.infer; const recordWithLiteralUnionKeys = z.record( z.union([z.literal("Tuna"), z.literal("Salmon"), z.literal(21)]), z.string() ); type recordWithLiteralUnionKeys = z.infer; enum Enum { Tuna = 0, Salmon = "Shark", } const recordWithTypescriptEnum = z.record(z.enum(Enum), z.string()); type recordWithTypescriptEnum = z.infer; expectTypeOf().toEqualTypeOf>(); expectTypeOf().toEqualTypeOf>(); expectTypeOf().toEqualTypeOf>(); expectTypeOf().toEqualTypeOf>(); expectTypeOf().toEqualTypeOf>(); }); test("enum exhaustiveness", () => { const schema = z.record(z.enum(["Tuna", "Salmon"]), z.string()); expect( schema.parse({ Tuna: "asdf", Salmon: "asdf", }) ).toEqual({ Tuna: "asdf", Salmon: "asdf", }); expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "Trout" ], "path": [], "message": "Unrecognized key: \\"Trout\\"" } ]], "success": false, } `); expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "Salmon" ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); }); test("optional-in value type", () => { const defaulted = z.record(z.enum(["Tuna", "Salmon"]), z.string().default("unknown")); expectTypeOf>().toEqualTypeOf>>(); expectTypeOf>().toEqualTypeOf>(); expect(defaulted.parse({ Tuna: "asdf" })).toEqual({ Tuna: "asdf", Salmon: "unknown" }); const prefaulted = z.record(z.enum(["Tuna", "Salmon"]), z.string().prefault("unknown")); expectTypeOf>().toEqualTypeOf>>(); expect(prefaulted.parse({ Tuna: "asdf" })).toEqual({ Tuna: "asdf", Salmon: "unknown" }); const optional = z.record(z.enum(["Tuna", "Salmon"]), z.string().optional()); expectTypeOf>().toEqualTypeOf>>(); // toStrictEqual, not toEqual: an exhaustive record assigns every key, and toEqual cannot tell an absent key from one holding undefined. expect(optional.parse({ Tuna: "asdf" })).toStrictEqual({ Tuna: "asdf", Salmon: undefined }); // A value that needs a slot keeps the key required, and a non-enumerable key stays an index signature either way. const required = z.record(z.enum(["Tuna", "Salmon"]), z.string()); expectTypeOf>().toEqualTypeOf>(); const indexed = z.record(z.string(), z.string().default("unknown")); expectTypeOf>().toEqualTypeOf>(); // A catch and a preprocess pipe declare no static optin, so the key stays required even where the parser can fill it. The static predicate and the one the JSON Schema emitter uses resolve these differently, and the two have to keep agreeing. const caught = z.record(z.enum(["Tuna", "Salmon"]), z.string().catch("unknown")); expectTypeOf>().toEqualTypeOf>(); const preprocessed = z.record( z.enum(["Tuna", "Salmon"]), z.preprocess((v) => v, z.string()) ); expectTypeOf>().toEqualTypeOf>(); }); test("typescript enum exhaustiveness", () => { enum BigFish { Tuna = 0, Salmon = "Shark", } const schema = z.record(z.enum(BigFish), z.string()); const value = { [BigFish.Tuna]: "asdf", [BigFish.Salmon]: "asdf", }; expect(schema.parse(value)).toEqual(value); expect(schema.safeParse({ [BigFish.Tuna]: "asdf", [BigFish.Salmon]: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "Trout" ], "path": [], "message": "Unrecognized key: \\"Trout\\"" } ]], "success": false, } `); expect(schema.safeParse({ [BigFish.Tuna]: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "Shark" ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); expect(schema.safeParse({ [BigFish.Salmon]: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ 0 ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); }); test("literal exhaustiveness", () => { const schema = z.record(z.literal(["Tuna", "Salmon", 21]), z.string()); schema.parse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", }); expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "Trout" ], "path": [], "message": "Unrecognized key: \\"Trout\\"" } ]], "success": false, } `); expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "Salmon" ], "message": "Invalid input: expected string, received undefined" }, { "expected": "string", "code": "invalid_type", "path": [ 21 ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); }); test("pipe exhaustiveness", () => { const schema = z.record(z.enum(["Tuna", "Salmon"]).pipe(z.any()), z.string()); expect(schema.parse({ Tuna: "asdf", Salmon: "asdf" })).toEqual({ Tuna: "asdf", Salmon: "asdf", }); expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "Trout" ], "path": [], "message": "Unrecognized key: \\"Trout\\"" } ]], "success": false, } `); expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "Salmon" ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); }); test("union exhaustiveness", () => { const schema = z.record(z.union([z.literal("Tuna"), z.literal("Salmon"), z.literal(21)]), z.string()); expect(schema.parse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf" })).toEqual({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", }); expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", 21: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "Trout" ], "path": [], "message": "Unrecognized key: \\"Trout\\"" } ]], "success": false, } `); expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "Salmon" ], "message": "Invalid input: expected string, received undefined" }, { "expected": "string", "code": "invalid_type", "path": [ 21 ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); }); test("applies transforms on the key schema (#5296)", () => { const single = z.record( z.literal("a").transform(() => "b" as const), z.string() ); expect(single.parse({ a: "John" })).toEqual({ b: "John" }); const multi = z.record( z.literal(["a", "b"]).transform((k) => k.toUpperCase()), z.number() ); expect(multi.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 }); // required-key semantics still hold when the keyType has a known value set expect(multi.safeParse({ a: 1 }).success).toBe(false); const en = z.record( z.enum(["a", "b"]).transform((k) => k.toUpperCase()), z.number() ); expect(en.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 }); // matches partialRecord, which already applied transforms const part = z.partialRecord( z.literal("a").transform(() => "b" as const), z.string() ); expect(part.parse({ a: "John" })).toEqual({ b: "John" }); }); test("surfaces key schema refinement failures as invalid_key", () => { // refine rejects "b" but it's still in the literal's value set const schema = z.record( z.literal(["a", "b"]).refine((k) => k === "a", { message: "only 'a' is allowed" }), z.string() ); expect(schema.safeParse({ a: "ok", b: "nope" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "invalid_key", "origin": "record", "issues": [ { "code": "custom", "path": [], "message": "only 'a' is allowed" } ], "path": [ "b" ], "message": "Invalid key in record" } ]], "success": false, } `); }); test("string record parse - pass", () => { const schema = z.record(z.string(), z.boolean()); schema.parse({ k1: true, k2: false, 1234: false, }); expect(schema.safeParse({ asdf: 1234 }).success).toEqual(false); expect(schema.safeParse("asdf")).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "record", "code": "invalid_type", "path": [], "message": "Invalid input: expected record, received string" } ]], "success": false, } `); }); test("key and value getters", () => { const rec = z.record(z.string(), z.number()); rec.keyType.parse("asdf"); rec.valueType.parse(1234); }); test("is not vulnerable to prototype pollution", async () => { const rec = z.record( z.string(), z.object({ a: z.string(), }) ); const data = JSON.parse(` { "__proto__": { "a": "evil" }, "b": { "a": "good" } } `); const obj1 = rec.parse(data); expect(obj1.a).toBeUndefined(); const obj2 = rec.safeParse(data); expect(obj2.success).toBe(true); if (obj2.success) { expect(obj2.data.a).toBeUndefined(); } const obj3 = await rec.parseAsync(data); expect(obj3.a).toBeUndefined(); const obj4 = await rec.safeParseAsync(data); expect(obj4.success).toBe(true); if (obj4.success) { expect(obj4.data.a).toBeUndefined(); } }); test("key schema cannot normalize an input key into __proto__", async () => { const value = z.object({ a: z.string() }); const payload = { a: "evil" }; const wire = (key: string) => JSON.parse(JSON.stringify({ [key]: payload })); const cases = [ [z.record(z.string().toLowerCase(), value), wire("__PROTO__")], [z.record(z.string().trim(), value), wire(" __proto__ ")], [z.record(z.string().normalize("NFKC"), value), wire("__proto__")], [ z.record( z.string().transform((s) => s.slice(2)), value ), wire("x:__proto__"), ], ] as const; for (const [schema, data] of cases) { const result = schema.parse(data); expect(Object.getPrototypeOf(result)).toBe(Object.prototype); expect(Object.keys(result)).toEqual([]); expect((result as any).a).toBeUndefined(); expect(Object.getPrototypeOf(await schema.parseAsync(data))).toBe(Object.prototype); } // an async value schema takes the promise write path const asyncValue = z.record( z.string().toLowerCase(), value.refine(async () => true) ); expect(Object.getPrototypeOf(await asyncValue.parseAsync(wire("__PROTO__")))).toBe(Object.prototype); // ordinary normalization still lands as an own key expect(z.record(z.string().toLowerCase(), value).parse({ KEY: payload })).toEqual({ key: payload }); }); test("dont remove undefined values", () => { const result1 = z.record(z.string(), z.any()).parse({ foo: undefined }); expect(result1).toEqual({ foo: undefined, }); }); test("allow undefined values", () => { const schema = z.record(z.string(), z.undefined()); expect( Object.keys( schema.parse({ _test: undefined, }) ) ).toEqual(["_test"]); }); test("async parsing", async () => { const schema = z .record( z.string(), z .string() .optional() .refine(async () => true) ) .refine(async () => true); const data = { foo: "bar", baz: "qux", }; const result = await schema.safeParseAsync(data); expect(result.data).toEqual(data); }); test("async parsing", async () => { const schema = z .record( z.string(), z .string() .optional() .refine(async () => false) ) .refine(async () => false); const data = { foo: "bar", baz: "qux", }; const result = await schema.safeParseAsync(data); expect(result.success).toEqual(false); expect(result.error).toMatchInlineSnapshot(` [ZodError: [ { "code": "custom", "path": [ "foo" ], "message": "Invalid input" }, { "code": "custom", "path": [ "baz" ], "message": "Invalid input" }, { "code": "custom", "path": [], "message": "Invalid input" } ]] `); }); test("partial record", () => { const schema = z.partialRecord(z.string(), z.string()); type schema = z.infer; expectTypeOf().toEqualTypeOf>>(); const Keys = z.enum(["id", "name", "email"]); //.or(z.never()); const Person = z.partialRecord(Keys, z.string()); expectTypeOf>().toEqualTypeOf>>(); Person.parse({ id: "123", // name: "John", // email: "john@example.com", }); Person.parse({ // id: "123", // name: "John", email: "john@example.com", }); expect(Person.def.keyType._zod.def.type).toEqual("enum"); }); test("partialRecord with z.literal([key, ...])", () => { const Keys = z.literal(["id", "name", "email"]); const schema = z.partialRecord(Keys, z.string()); type Schema = z.infer; expectTypeOf().toEqualTypeOf>>(); // Should parse valid partials expect(schema.parse({})).toEqual({}); expect(schema.parse({ id: "1" })).toEqual({ id: "1" }); expect(schema.parse({ name: "n", email: "e@example.com" })).toEqual({ name: "n", email: "e@example.com" }); // Should fail with unrecognized key, error checked via inline snapshot expect(schema.safeParse({ foo: "bar" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "code": "unrecognized_keys", "keys": [ "foo" ], "path": [], "message": "Unrecognized key: \\"foo\\"" } ]], "success": false, } `); }); test("partialRecord with numeric literal keys", () => { const Keys = z.literal([1, 2, 3]); const schema = z.partialRecord(Keys, z.string()); type Schema = z.infer; expectTypeOf().toEqualTypeOf>>(); // Should parse valid partials with numeric keys (as strings in JS objects) expect(schema.parse({})).toEqual({}); expect(schema.parse({ 1: "one" })).toEqual({ 1: "one" }); expect(schema.parse({ 2: "two", 3: "three" })).toEqual({ 2: "two", 3: "three" }); // Should fail with unrecognized key expect(schema.safeParse({ 4: "four" }).success).toBe(false); }); test("partialRecord with union of string and numeric literal keys", () => { const StringKeys = z.literal(["a", "b", "c"]); const NumericKeys = z.literal([1, 2, 3]); const schema = z.partialRecord(z.union([StringKeys, NumericKeys]), z.string()); type Schema = z.infer; expectTypeOf().toEqualTypeOf>>(); // Should parse valid partials with mixed keys expect(schema.parse({})).toEqual({}); expect(schema.parse({ a: "1", 2: "4" })).toEqual({ a: "1", 2: "4" }); expect(schema.parse({ a: "a", b: "b", 1: "1", 2: "2" })).toEqual({ a: "a", b: "b", 1: "1", 2: "2" }); // Should fail with unrecognized key expect(schema.safeParse({ d: "d" }).success).toBe(false); expect(schema.safeParse({ 4: "4" }).success).toBe(false); }); test("looseRecord passes through non-matching keys", () => { const schema = z.looseRecord(z.string().regex(/^S_/), z.string()); // Keys matching pattern are validated expect(schema.parse({ S_name: "John" })).toEqual({ S_name: "John" }); expect(() => schema.parse({ S_name: 123 })).toThrow(); // wrong value type // Keys not matching pattern pass through unchanged expect(schema.parse({ S_name: "John", other: "value" })).toEqual({ S_name: "John", other: "value" }); expect(schema.parse({ S_name: "John", count: 123 })).toEqual({ S_name: "John", count: 123 }); expect(schema.parse({ other: "value" })).toEqual({ other: "value" }); }); test("looseRecord with closed key schema passes through unrecognized keys", () => { const enumSchema = z.looseRecord(z.enum(["foo", "bar"]), z.any()); expect(enumSchema.parse({ foo: 123, bar: {}, baz: null })).toEqual({ foo: 123, bar: {}, baz: null, }); const literalSchema = z.looseRecord(z.literal(["foo", "bar"]), z.any()); expect(literalSchema.parse({ foo: 123, bar: {}, baz: null })).toEqual({ foo: 123, bar: {}, baz: null, }); // Recognized keys are still validated const validated = z.looseRecord(z.enum(["foo", "bar"]), z.string()); expect(validated.parse({ foo: "ok", bar: "ok", baz: 123 })).toEqual({ foo: "ok", bar: "ok", baz: 123, }); expect(() => validated.parse({ foo: 123 })).toThrow(); }); test("record with closed key schema still rejects unrecognized keys", () => { const schema = z.record(z.enum(["foo", "bar"]), z.any()); expect(schema.safeParse({ foo: 123, bar: {}, baz: null }).success).toBe(false); }); // __proto__ in input must not replace the prototype of the parsed object via the assignment setter on the result {}. https://github.com/colinhacks/zod/security/advisories/GHSA-r34p-xfmx-58wv test("looseRecord with closed key schema drops __proto__", () => { const schema = z.looseRecord(z.enum(["foo", "bar"]), z.any()); const parsed = schema.parse(JSON.parse('{"foo":1,"bar":2,"__proto__":{"isAdmin":true}}')); expect(Object.keys(parsed)).toEqual(["foo", "bar"]); expect((parsed as any).isAdmin).toBeUndefined(); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); }); test("intersection of loose records", () => { const schema = z.intersection( z.object({ name: z.string() }).passthrough(), z.intersection( z.looseRecord(z.string().regex(/^S_/), z.string()), z.looseRecord(z.string().regex(/^N_/), z.number()) ) ); // Each pattern validates its matching keys const result = schema.parse({ name: "John", S_foo: "bar", N_count: 123 }); expect(result.name).toBe("John"); expect(result.S_foo).toBe("bar"); expect(result.N_count).toBe(123); // Keys not matching any pattern pass through const result2 = schema.parse({ name: "John", S_foo: "bar", N_count: 123, other: "value" }); expect(result2.other).toBe("value"); // Validation errors still occur for matching keys expect(() => schema.parse({ name: "John", S_foo: 123 })).toThrow(); // S_foo should be string expect(() => schema.parse({ name: "John", N_count: "abc" })).toThrow(); // N_count should be number }); test("object with looseRecord index signature", () => { // Simulates TypeScript index signature: { label: string; [key: `label:${string}`]: string } const schema = z.object({ label: z.string() }).and(z.looseRecord(z.string().regex(/^label:[a-z]{2}$/), z.string())); type Schema = z.infer; expectTypeOf().toEqualTypeOf<{ label: string } & Record>(); // Valid: has required property and matching pattern keys expect(schema.parse({ label: "Purple", "label:en": "Purple", "label:ru": "Пурпурный" })).toEqual({ label: "Purple", "label:en": "Purple", "label:ru": "Пурпурный", }); // Valid: just required property expect(schema.parse({ label: "Purple" })).toEqual({ label: "Purple" }); // Invalid: missing required property expect(schema.safeParse({ "label:en": "Purple" })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "label" ], "message": "Invalid input: expected string, received undefined" } ]], "success": false, } `); // Invalid: pattern key with wrong value type expect(schema.safeParse({ label: "Purple", "label:en": 123 })).toMatchInlineSnapshot(` { "error": [ZodError: [ { "expected": "string", "code": "invalid_type", "path": [ "label:en" ], "message": "Invalid input: expected string, received number" } ]], "success": false, } `); }); test("numeric string keys", () => { const schema = z.record(z.number(), z.number()); // Numeric string keys work expect(schema.parse({ 1: 100, 2: 200 })).toEqual({ 1: 100, 2: 200 }); expect(schema.parse({ "1.5": 100, "-3": 200 })).toEqual({ "1.5": 100, "-3": 200 }); // Non-numeric keys fail expect(schema.safeParse({ abc: 100 }).success).toBe(false); // Integer constraint is respected const intSchema = z.record(z.number().int(), z.number()); expect(intSchema.parse({ 1: 100 })).toEqual({ 1: 100 }); expect(intSchema.safeParse({ "1.5": 100 }).success).toBe(false); // Transforms on numeric keys work const transformedSchema = z.record( z.number().overwrite((n) => n * 2), z.string() ); expect(transformedSchema.parse({ 5: "five", 10: "ten" })).toEqual({ 10: "five", 20: "ten" }); }); test("v3-compat single-arg form: z.record(valueType)", () => { // single arg should default keyType to z.string() and use the arg as valueType const schema = (z.record as any)(z.number()); expect(schema.keyType._zod.def.type).toEqual("string"); expect(schema.valueType._zod.def.type).toEqual("number"); expect(schema.parse({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 }); expect(schema.safeParse({ a: "x" }).success).toBe(false); // params still flow through in the single-arg form const withMessage = (z.record as any)(z.number(), "must be a number record"); expect(withMessage.keyType._zod.def.type).toEqual("string"); expect(withMessage.valueType._zod.def.type).toEqual("number"); // toJSONSchema should produce a well-formed schema (regression: previously produced additionalProperties from undefined valueType, crashing process()) const json = z.toJSONSchema(schema); expect(json).toMatchObject({ type: "object", propertyNames: { type: "string" }, additionalProperties: { type: "number" }, }); }); test("__proto__ in a finite key set is stripped", () => { const data = JSON.parse('{"__proto__":{"a":"declared"},"b":{"a":"good"}}'); for (const schema of [ z.record(z.enum(["__proto__", "b"]), z.object({ a: z.string() })), z.record(z.literal(["__proto__", "b"]), z.object({ a: z.string() })), ]) { const parsed: any = schema.parse(data); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); expect(Object.prototype.hasOwnProperty.call(parsed, "__proto__")).toBe(false); expect(Object.keys(parsed)).toEqual(["b"]); expect(parsed.a).toBeUndefined(); } expect(({} as any).a).toBeUndefined(); }); test("a raw __proto__ input key stays skipped in loose mode", () => { const parsed: any = z.looseRecord(z.iso.datetime(), z.unknown()).parse(JSON.parse('{"__proto__":{"a":1}}')); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); expect(Object.prototype.hasOwnProperty.call(parsed, "__proto__")).toBe(false); }); test("partialRecord strips a declared __proto__ key", () => { const schema = z.partialRecord(z.enum(["__proto__", "b"]), z.string()); const parsed: any = schema.parse(Object.fromEntries([["__proto__", "declared"]])); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); expect(Object.prototype.hasOwnProperty.call(parsed, "__proto__")).toBe(false); expect(parsed).toEqual({}); expect(schema.parse({})).toEqual({}); expect(schema.safeParse({ other: "x" }).success).toBe(false); }); test("partialRecord strips a declared __proto__ key in loose mode", () => { const key = z.enum(["__proto__"]).refine(() => false); const schema = z.partialRecord(key, z.unknown(), { mode: "loose" }); const value = { marker: true }; const parsed: any = schema.parse(Object.fromEntries([["__proto__", value]])); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); expect(Object.prototype.hasOwnProperty.call(parsed, "__proto__")).toBe(false); expect(parsed).toEqual({}); expect(parsed.marker).toBeUndefined(); }); test("partial is internal to partialRecord", () => { // @ts-expect-error partial is not a public record parameter z.record(z.enum(["a"]), z.string(), { partial: true }); const schema = z.partialRecord(z.enum(["a"]), z.string(), { partial: false } as any); expect(schema.parse({})).toEqual({}); }); test("partialRecord strips a declared __proto__ key before transforms", () => { const schema = z.partialRecord( z.literal("__proto__").transform(() => "safe" as const), z.string() ); expect(schema.parse(Object.fromEntries([["__proto__", "value"]]))).toEqual({}); }); test("a finite __proto__ key is ignored whether present or missing", () => { const schema = z.record(z.enum(["__proto__"]), z.string()); const parsed: any = schema.parse({}); expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype); expect(Object.prototype.hasOwnProperty.call(parsed, "__proto__")).toBe(false); expect(schema.parse(Object.fromEntries([["__proto__", 123]]))).toEqual({}); });