question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

feature request: combining/nesting/extending discriminated unions

See original GitHub issue

In our app we have some data coming from an external service that’s modelled as a combination of 2 discriminated unions, e.g.

[
  { type: "quote", attribution: "..." },
  { type: "textAndMedia", mediaType: "image", image: {...} }
  { type: "textAndMedia", mediaType: "video", video: {...} }
]

But attempting to model it with zod fails with the error:
The discriminator value could not be extracted from all the provided schemas

const t = z.discriminatedUnion("type", [
  z.object({ type: z.literal("one"), foo: z.string() }),
  z.object({ type: z.literal("two"), bar: z.string() }),
  z.discriminatedUnion("secondType", [
    { type: z.literal("three"), secondType: z.literal("a") },
  ]),
]);

An extra problem we’ve ran into is the nested discriminator is defined elsewhere, but unlike objects it doesn’t have a .extend method, and a ZodDiscriminatedUnion isn’t a valid arg for ZodObject.merge

const otherDiscriminator = z.discriminatedUnion("secondType", [
  z.object({ secondType: z.literal("a") }),
  z.object({ secondType: z.literal("b") }),
]);
z.discriminatedUnion("type", [
  z.object({ type: z.literal("one"), foo: z.string() }),
  z.object({ type: z.literal("two"), bar: z.string() }),
  otherDiscriminator.extend({ type: z.literal("three") }),
]);
Instead of extending I considered extracting the discriminator options and mapping over them, but zod can't infer that correctly. Code sample in toggle

const otherDiscriminatorOptions = [
  z.object({ secondType: z.literal("a") }),
  z.object({ secondType: z.literal("b") }),
] as const;

const otherDiscriminator = z.discriminatedUnion("secondType", [
  ...otherDiscriminatorOptions,
]);

z.discriminatedUnion("type", [
  z.object({ type: z.literal("one"), foo: z.string() }),
  z.object({ type: z.literal("two"), bar: z.string() }),

  z.discriminatedUnion("secondType", [
    ...otherDiscriminatorOptions.map((option) => ({
      type: z.literal("three"),
      ...option,
    })),
  ]),
]);

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:2
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
jasonsilbermancommented, Oct 13, 2022

Wanted to bump as having the ability to use a discriminated union with extend/merge would be really, really nice!

1reaction
sdirosacommented, Nov 25, 2022

@maxArturo nice!

I can confirm that your changes to allow using a ZodDiscriminatedUnion as an element of other discriminated unions fixes the issue. Requiring the discriminated unions to share the same discrimination key seems reasonable to me.

In our specific case all of the unions we are discriminating, and occasionally nesting, have the same exact discrimination key. Also, the key is valued uniquely across all objects.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Proposal: Add Discriminated Unions using a new Type #14208
Although c# 7 contains various features for pattern matching, ... a proposal for adding Discriminated Union types, with exhaustive matching.
Read more >
Discriminated Unions and Exhaustiveness Checking in ...
In this article, you'll find an example of what we learned about discriminated unions and exhaustiveness checking in Typescript and why it's ...
Read more >
Demystifying TypeScript Discriminated Unions - CSS-Tricks
TypeScript discriminated unions are types where a key or value can be used to differentiate between the keys and values of several types...
Read more >
Discriminated Unions - F# | Microsoft Learn
Discriminated unions provide support for values that can be one of a number of named cases, possibly each with different values and types....
Read more >
type safety - Discriminated union in C# - Stack Overflow
I like the direction of the accepted solution but it doesn't scale well for unions of more than three items (e.g. a union...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found