Skip to content

Loosen z.strictObject() inside intersection#5587

Merged
colinhacks merged 1 commit intomainfrom
improve-strict-object-inside-intersection
Dec 31, 2025
Merged

Loosen z.strictObject() inside intersection#5587
colinhacks merged 1 commit intomainfrom
improve-strict-object-inside-intersection

Conversation

@colinhacks
Copy link
Owner

@colinhacks colinhacks commented Dec 31, 2025

Previously strict objects were functionality incompatible with intersections, as the inner strict object would throw on any unrecognized key. Now, this is loosened inside of intersections. Any key recognized by at least one side of the intersection will now pass validation:

const A = z.strictObject({ a: z.string() });
const B = z.object({ b: z.string() });

const C = z.intersection(A, B);

// Keys recognized by either side now work
C.parse({ a: "foo", b: "bar" }); // ✅ { a: "foo", b: "bar" }

// Extra keys are stripped (follows strip behavior from B)
C.parse({ a: "foo", b: "bar", c: "extra" }); // ✅ { a: "foo", b: "bar" }

When both sides are strict, keys unrecognized by both sides will still error:

const A = z.strictObject({ a: z.string() });
const B = z.strictObject({ b: z.string() });

const C = z.intersection(A, B);

// Keys recognized by either side work
C.parse({ a: "foo", b: "bar" }); // ✅

// Keys unrecognized by BOTH sides error
C.parse({ a: "foo", b: "bar", c: "extra" }); 
// ❌ ZodError: Unrecognized key: "c"

Copilot AI review requested due to automatic review settings December 31, 2025 01:02
@colinhacks colinhacks changed the title Loosen strictObjectinside intersection Loosen z.strictObject() inside intersection Dec 31, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modifies the intersection logic for Zod schemas to loosen the behavior when strict objects are intersected. Instead of reporting all unrecognized keys from either side, the new logic only reports keys that are unrecognized by BOTH sides of the intersection. This allows keys recognized by either schema to pass validation.

Key changes:

  • Updated handleIntersectionResults to track which side reports each key as unrecognized
  • Modified logic to only create an error for keys rejected by both schemas
  • Added tests demonstrating the new behavior for strict+strip and strict+strict intersections

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/zod/src/v4/core/schemas.ts Implements new intersection logic that filters unrecognized_keys issues to only report keys unrecognized by both sides
packages/zod/src/v4/classic/tests/intersection.test.ts Updates existing test and adds new tests to validate the loosened strict object intersection behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@pullfrog pullfrog bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change loosens strictObject behavior in intersections by only rejecting keys that both sides don't recognize. The approach is sound and the implementation is correct. The tests clearly demonstrate the intended behavior for strict+strip and strict+strict cases.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow runpullfrog.com𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant