Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.strict() and .and() combined is not working #390

Closed
fabien0102 opened this issue Apr 11, 2021 · 7 comments
Closed

.strict() and .and() combined is not working #390

fabien0102 opened this issue Apr 11, 2021 · 7 comments

Comments

@fabien0102
Copy link

Bug description

The method .strict() and .and() combined results in an unexpected parsing error.

Zod version

3.0.0-alpha.33

Playground

const a = z.object({ a: z.string() }).strict();
const b = z.object({ b: z.string() }).strict();
const c = a.and(b);

c.parse({ a: "a", b: "b" });

Output

error: ZodError: [
    {
      "code": "unrecognized_keys",
      "keys": [
        "b"
      ],
      "path": [],
      "message": "Unrecognized key(s) in object: 'b'"
    },
    {
      "code": "unrecognized_keys",
      "keys": [
        "a"
      ],
      "path": [],
      "message": "Unrecognized key(s) in object: 'a'"
    }
  ]
@colinhacks
Copy link
Owner

This is expected. The .and method creates a "dumb" intersection. It passes the input into both A and B. If they both pass, validation is considered successful. Because A and B both individually don't allow unrecognized keys, they both fail. Get rid of the .strict() calls if you want this to work.

If you're just looking to merge two objects, use .merge which more like you expect. It also returns a new ZodObject instance instead of a ZodIntersection.

const a = z.object({ a: z.string() });
const b = z.object({ b: z.string() });
const c = a.merge(b).strict();

Small side-note, when doing A.merge(B), the resulting object inherits its strictness setting from A.

@fabien0102
Copy link
Author

Thanks for the explanations.

Sadly, this .merge doesn't really solved my issue, and I think I found another issue 🙄

const a = z.object({ a: z.string(), b: z.number() });
const b = z.object({ b: z.string() });
const c = a.merge(b).strict(); // { a: string; b: never }

// Passed
c.parse({ a: "test", b: "42" });

// Failed
c.parse({ a: "test", b: 42 });

The z.infer<typeof c>["b"] is never instead of string (regarding the actual validation behaviour)

Anyway, I can't use this merge to translate a typescript intersection in the context of ts-to-zod.

@colinhacks
Copy link
Owner

colinhacks commented Apr 25, 2021

Good catch! I relatively recently changed the behavior of "merge" to behave more like "extend". I forgot to update the inferred type. Fixed in alpha.38.

Like you say, merge isn't an intersection, it just merges the sets of properties from A and B into a new object. In the case of a clash, the properties of B override the properties of A. I guess there isn't a way do what you're trying to do. You'll have to get rid of the .strict() calls if you want the intersection to work properly. In fact, part of the reason the default behavior was changed from "strict" to "strip" was so intersections would work on "plain" ZodObjects.

Is there a reason you need strict checking? I'd recommend against having ts-to-zod generate strict ZodObjects by default, but it's totally your call.

@colinhacks
Copy link
Owner

By the way, I just added an Ecosystem section to the README to boost projects like yours: https://github.com/colinhacks/zod/tree/v3#ecosystem

@fabien0102
Copy link
Author

Is there a reason you need strict checking?

No reason at all, was just to be "feature complete", but I will probably drop this idea (and my plan was to put this an option, not the default)

@colinhacks
Copy link
Owner

Gotcha. Loving your work on this so far! Sorry it took so long to respond here, just started a new job. Should be more responsive in the future. Feel free to DM me on Twitter @colinhacks as well for a speedier response.

@fabien0102
Copy link
Author

Don't worry, I also have a lot of work and I totally understand than side-projects are not always a priority (and can be sometime hard to manage on top of all other stuff going on 😅 )

manugoyal added a commit to braintrustdata/braintrust-sdk that referenced this issue Mar 31, 2024
After #166, we
moved to using strict objects by default. Apparently creating
intersections between two strict objects (e.g.
`braintrustModelParamsSchema` and `openAIModelParamsSchema`) doesn't
seem to work at all. We have to use `merge` to make everything work.

See colinhacks/zod#390 for an explanation of
the issue.
manugoyal added a commit to braintrustdata/braintrust-sdk that referenced this issue Mar 31, 2024
After #166, we
moved to using strict objects by default. Apparently creating
intersections between two strict objects (e.g.
`braintrustModelParamsSchema` and `openAIModelParamsSchema`) doesn't
seem to work at all. We have to use `merge` to make everything work.

See colinhacks/zod#390 for an explanation of
the issue.
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

No branches or pull requests

2 participants