Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use zod discriminatedUnion with an enum discriminator without typing out all enum possibilities

I'm trying to use zod schema validation to validate some data that has different constraints based on the value of an enumeration field (prisma generated enum type). Basically it can take these two shapes:

{ discriminatorField: "VAL1", otherField: "any string" }

{ discriminatorField: "any other allowed string besides VAL1", otherField: undefined }

It seems this can be done with z.discriminatedUnion() in the following way:

const schema = z.discriminatedUnion("discriminatorField", [
   z.object({ discriminatorField: z.literal("VAL1"), otherField: z.string()}),
   z.object({ discriminatorField: z.literal("VAL2"), otherField: z.string().optional()}),
   // ... have to type out all possible enum values as literal conditions here?
])

This works, but you have to type out all possible enum values to discriminate on. I tried using z.nativeEnum(MyEnum) instead of z.literal("VAL2") in the code above, but zod then complains that the values are overlapping, which is of course true, but I hoped it would just use the first case that matches.

like image 346
Adrian Schweizer Avatar asked Sep 16 '25 05:09

Adrian Schweizer


1 Answers

const schema = z.discriminatedUnion("discriminatorField", [
  z.object({ discriminatorField: z.literal("VAL1"), otherField: z.string() }),
  ...Object.values(MyEnum)
    .filter((enum) => enum !== "VAL1")
    .map((enum) =>
      z.object({
        discriminatorField: z.literal(enum),
        otherField: z.string().optional(),
      }),
    ),
]);
like image 165
Michael Arrabito Avatar answered Sep 19 '25 05:09

Michael Arrabito