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

Using discriminatedUnion with schemas typed as z.ZodType<MyType> raise TS error #3898

Open
robmonie opened this issue Dec 10, 2024 · 2 comments

Comments

@robmonie
Copy link

We have a fairly complex recursive set of types and schemas that require us to define our types before our schemas and use z.ZodType when defining schemas. This is along the lines of this pattern - https://zod.dev/?id=recursive-types

We've noticed that when we define our schemas this way we get type errors when trying to create a discriminated union on these types.

A simple reproduction

This compiles fine.

const catSchema = z.object({type: z.literal('cat'), scratches: z.boolean()})
const dogSchema = z.object({type: z.literal('dog'), barks: z.boolean()})
const petSchema = z.discriminatedUnion('type', [catSchema, dogSchema]);

type Cat = z.infer<typeof catSchema>;
type Dog = z.infer<typeof dogSchema>;
type Pet = z.infer<typeof petSchema>;

This won't compile and results in the ts error following

type Cat = { type: 'cat'; scratches: boolean;};
type Dog = { type: 'dog'; barks: boolean;};
type Pet = Cat | Dog;

const catSchema: z.ZodType<Cat> = z.object({type: z.literal('cat'), scratches: z.boolean()})
const dogSchema: z.ZodType<Dog>= z.object({type: z.literal('dog'), barks: z.boolean()})
const petSchema: z.ZodType<Pet>  = z.discriminatedUnion('type', [catSchema, dogSchema]);
Type 'ZodType<Cat, ZodTypeDef, Cat>' is missing the following properties from type 'ZodObject<{ type: ZodTypeAny; } & ZodRawShape, UnknownKeysParam, ZodTypeAny, { [x: string]: any; type?: unknown; }, { [x: string]: any; type?: unknown; }>': _cached, _getCached, shape, strict, and 14 more.ts(2740)

Is there a supported way to achieve discriminated unions on schemas defined in this way?

@colinhacks
Copy link
Owner

Yeah, unfortunately that won't work as those recursive schemas are types as ZodType, whereas z.discriminatedUnion only accepts object types at the moment. This is one of the fundamental problems I'm aiming to solve with Zod's next major version (coming soon™)

@robmonie
Copy link
Author

Thanks for replying to quickly Colin.

The reason this has come up for us now is that we faced a sudden and dramatic parsing performance issue on a largish dataset after adding one more type to the existing union of six types (not discriminated). I remembered reading at an earlier time that using a regular union vs discriminated could be quite a bit less performant due to the need to test for each during parsing so I tried moving to discriminated and was reminded of why they weren't initially setup like that.

Interestingly as an experiment I annotated the type errors caused by changing to a discriminated union with @ts-ignore and parsing was very fast but it also worked which I wasn't necessarily expecting. I haven't explored why this is ok or whether it's safe to do in the interim yet but it certainly shows the difference in performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants