Open dbeckwith opened 2 years ago
Yeah, all of those cases seem reasonable. Furthermore, true
/false
/Number
should be valid discriminator types. Basically, it would be good to support any value that TypeScript itself supports, and I think with Map
we can get the right behavior. PRs welcome!
Another one is intersection
:
z.discriminatedUnion('method', [
z.intersection(
z.object({ 'method': 'get' }),
getSchema,
),
z.intersection(
z.object({ 'method': 'put' }),
putSchema,
),
])
That one can almost be solved by using .merge
instead of .intersection
but that's not always possible. .union
/.or
also poses a challenge.
It seems zod not support null and undefined discriminants.
For example I want to define the structure: https://github.com/microsoft/TypeScript/pull/27631
type Result<T> = { error?: undefined, value: T } | { error: Error };
I test this code but report error:
type Result = { error?: undefined, value: string } | { error: Error };
const ResultSchema = z.discriminatedUnion('error', [
z.object({error: z.string().min(1)}),
z.object({error: z.undefined(), value: z.string().min(1)}),
]);
@dbeckwith, @scotttrinh, check out https://github.com/colinhacks/zod/pull/1213, which at least partially solves these issues.
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.
Pinging to see if that unmarks this with the stale bot. Apologies to all receiving notifications.
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.
I would also appreciate more flexible discriminated union input types. I don't think I'll have time to look at the code for a while but I am willing to take a stab at it.
Mainly commenting to un-stale this issue because I think it's important. Right now my code works fine with regular union
, but the resulting error messages are crappy, so I would rather use discriminatedUnion
, but my parsers are a bit too complicated I guess.
I ran into this earlier and thought the same thing as the commenters here. @scotttrinh @colinhacks I'd love to take a stab at submitting a PR that solves this generally.
Also @dbeckwith @tianhuil while triaging, enums seem to work as of 6ce18f3 (you can verify this with the following code in playground.ts
):
/**
* the discriminator is an enum ==> this works as of 6ce18f3
*/
const C = z.object({ type: z.literal("c") });
const E = z.object({ type: z.enum(["e", "ee", "eee"]) });
const CorE = z.discriminatedUnion("type", [C, E]);
CorE.parse({ type: "e" });
Please take a look at #1589, would love to know your thoughts. It addresses several of the issues listed here:
The following are now well-supported discriminator values (enum/undefined could have been already)
z.undefined()
z.null()
z.enum()
z.discriminatedUnion()
Would it be possible to add support for using a union as a discriminator value?
It seems like
z.discriminatedUnion
currently has quite narrow requirements for what you can use it with. Here are some example use cases that seem sound to me (in the sense that the discriminator should still be able to uniquely determine the union member) but currently aren't allowed:Any chance these cases can be supported? It would great if the requirement for discriminated union members could be widened to something like "any type that has the discriminator as a field and the type of the discriminator is a subtype of
string | null | undefined
and is mutually exclusive between the discriminated union members", but supporting at least the cases I mentioned above would still be much appreciated.