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

discriminatedUnion errors with z.object().transform() #1477

Closed
caillou opened this issue Oct 10, 2022 · 5 comments
Closed

discriminatedUnion errors with z.object().transform() #1477

caillou opened this issue Oct 10, 2022 · 5 comments
Labels
stale No activity in last 60 days

Comments

@caillou
Copy link

caillou commented Oct 10, 2022

Playground

import { z } from 'zod';

const ZodFoo = z.object({type: z.literal('foo'), foo: z.string()})
  .transform(({type, foo}) => ({type, value: foo}));
const ZodBar = z.object({type: z.literal('bar'), bar: z.string()})
  .transform(({type, bar}) => ({type, value: bar}));

const ZodBaz = z.discriminatedUnion('type', [ZodFoo, ZodBar]);

I am not sure if this is even possible.

If not, is there a recommended workaround?

@azhiv
Copy link
Contributor

azhiv commented Oct 12, 2022

What exactly are you trying to achieve? Discriminating types usually result in several different types. In your case they are both of the same one:

{
  type: 'foo' | 'bar',
  value: string;
}

If the main purpose of the transformations are further manipulations/refinements, will this be suitable for your needs:

const ZodFoo = zod.object({type: zod.literal('foo'), foo: zod.string()});
const ZodBar = zod.object({type: zod.literal('bar'), bar: zod.string()});
const ZodBaz = zod.discriminatedUnion('type', [ZodFoo, ZodBar])
  .transform(obj => ({
      type: obj.type,
      value: obj.type === 'foo' ? obj.foo : obj.bar,
  }));

?

@caillou
Copy link
Author

caillou commented Oct 13, 2022

@azhiv thanks for your feedback. I tried to reduce the example to a minimum for the sake of simplicity. Yet I did not succeed ;)

Let me try again:

Playground

const ZodFoo = z.object({type: z.literal('foo'), foo: z.string()});
const ZodBar = z.object({type: z.literal('bar'), bar: z.string().optional(), fallback: z.string()})
  .transform(({type, bar, fallback}) => ({type, bar: bar || fallback}));
const ZodBaz = z.discriminatedUnion('type', [ZodFoo, ZodBar]);

@azhiv
Copy link
Contributor

azhiv commented Oct 13, 2022

Ok, I couldn't find a way to combine transform with discriminatedUnion, maybe you're right and this is simply not supported.
The approach below is not that elegant and may be not something you were looking for, but If you possess control over the input types, I'd suggest defining a type with all transformations applied, so that the validation schema could be simplified. In the example above, you could define a separate getter like deducedBar returning bar || fallback, and then define a schema for this object, providing it to discriminatedUnion. Hope that helps!

@roblabat
Copy link
Contributor

roblabat commented Oct 28, 2022

Duplicate of #1171 with the openned PR #1290 fixing this issue and waiting for feed back or merge.

@stale
Copy link

stale bot commented Jan 26, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale No activity in last 60 days label Jan 26, 2023
@stale stale bot closed this as completed Feb 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale No activity in last 60 days
Projects
None yet
Development

No branches or pull requests

3 participants