zod icon indicating copy to clipboard operation
zod copied to clipboard

Q: why discriminatedUnion of one element is not possible

Open dearlordylord opened this issue 1 year ago • 3 comments

According to discriminatedUnion type definition, it accepts a list of at least two elements.

My question is why is this implemented like this?

Question arose for the reason that I have a real use case where I have a factory function that would return parsers for n>=1 string literals i.e.

const makeApiIdParser = (literals: NonEmptyArray<string>) => z.preprocess(
  (uuid) => {
    if (typeof uuid !== 'string') throw new Error('must be a string');
    const [type, id] = uuid.split(SEPARATOR);
    return { type, id };
  },
  z.discriminatedUnion('type', literals.map((type) => z.object({
    type: z.literal(type),
    id: z.string(),
  })))
);

This function would generate parsers for such strings as user::27f4ee03-e79e-470c-8d4e-fa28e8ac6089 but also a separate parsers for such strings as blog::7fe494ab-a349-4896-87f2-24e2024d2cce or collective::69e23e02-546b-4c30-a532-b3f45e8498f8

I could get by with if/else checking for my literals length, but it goes against normal intuition and would be akin to doing

const map = <T, R>(a: T[], f: (t: T) => R): R[] => {
  if (!a.length) return a;
  return a.map(f);
}

I hope this is a clear enough parallel to why I see the definition of discriminatedUnion as a bit weird.

There must be some technical restriction I don't see or some logical aspect I fail to recognize.

Could someone please help me to understand the reason for this implementation of discriminatedUnion?

dearlordylord avatar Sep 30 '22 03:09 dearlordylord