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

[Bug ?] Zod union ignoring zod object when fields are z.optional() #3562

Open
Siirko opened this issue Jun 10, 2024 · 3 comments
Open

[Bug ?] Zod union ignoring zod object when fields are z.optional() #3562

Siirko opened this issue Jun 10, 2024 · 3 comments

Comments

@Siirko
Copy link

Siirko commented Jun 10, 2024

Hi,

Basically, when doing zod objects and doing an union on that, when the second object of the union has optional fields, parsing just ignore it ! Is that normal ? I can't find any information about that. I've came with a solution using discriminatedUnion but that feels a little bit dirty ...

I've created a reproduction environment for replaying the issue
https://stackblitz.com/edit/typescript-f8ppcz?file=schemas%2FschemaWithDefaultType.ts

import { z } from 'zod';

const say = console.info;

function zod_optional_union_ignored() {
  // ! when one and two are optional,
  const type2 = z.object({
    one: z.number().optional(),
    two: z.number().optional(),
  });

  const type1 = z.object({
    three: z.number().optional(),
  });

  const type2or1 = z.union([type1, type2]);

  const test_data = {
    one: 1,
    two: 2,
  };

  const validatedTestData = type2or1.parse(test_data);

  // ! type2 is ignored, why is that ??
  say('zod optional type2 object ignored', { validatedTestData });

  const test_data2 = {
    three: 3,
  };

  // type1 is parsed correctly
  const validatedTestData2 = type2or1.parse(test_data2);
  say('zod optional type1 object not ignored', { validatedTestData2 });
}

function zod_union_not_ignored() {
  const type2 = z.object({
    one: z.number(),
    two: z.number(),
  });

  const type1 = z.object({
    three: z.number(),
  });

  const type2or1 = z.union([type1, type2]);

  const test_data = {
    one: 3,
    two: 2,
  };

  const validatedTestData = type2or1.parse(test_data);

  // type2 is parsed correctly here, certainly because there is no optional
  say('zod optional ingored', { validatedTestData });
}

zod_optional_union_ignored();
zod_union_not_ignored();

image

@Siirko Siirko changed the title Zod union ignoring zod object when fields are optional [Bug ?] Zod union ignoring zod object when fields are optional Jun 10, 2024
@Siirko Siirko changed the title [Bug ?] Zod union ignoring zod object when fields are optional [Bug ?] Zod union ignoring zod object when fields are z.optional() Jun 10, 2024
@samchungy
Copy link
Contributor

samchungy commented Jun 11, 2024

It's passing because your payload is valid against the first object in the union. You could fix this by enforcing strict objects

@Siirko
Copy link
Author

Siirko commented Jun 11, 2024

It's passing because your payload is valid against the first object in the union. You could fix this by enforcing strict objects

But why in the first section type2 is ignored ?

@samchungy
Copy link
Contributor

samchungy commented Jun 12, 2024

Because it successfully validated against the first object.

Zod will test the input against each of the "options" in order and return the first value that validates successfully.

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