zod icon indicating copy to clipboard operation
zod copied to clipboard

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

Open aaalloc opened this issue 8 months ago • 3 comments

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

aaalloc avatar Jun 10 '24 18:06 aaalloc