Reputation: 554
I have the following discriminated union:
enum Option {
FULL = 'FULL',
TIME_PERIOD = 'TIME_PERIOD',
MONTH = 'MONTH',
}
const schema = z.discriminatedUnion('option', [
z.object({ option: z.literal(Option.FULL) }),
z.object({
option: z.literal(Option.TIME_PERIOD),
from: z.date(),
to: z.date(),
}),
z.object({ option: z.literal(Option.MONTH), month: z.date() }),
])
Now I want to refine the second object, to check if the date from
is before to
:
const schema = z.discriminatedUnion('option', [
z.object({ option: z.literal(Option.FULL) }),
z.object({
option: z.literal(Option.TIME_PERIOD),
from: z.date(),
to: z.date(),
}).refine(
({ from, to }) => isBefore(from, to),
{
message: '"from" must be before "to"',
path: ['from'],
}
),
z.object({ option: z.literal(Option.MONTH), month: z.date() }),
])
But this gives me an error, basically saying "type ZodEffects is not allowed as ZodDiscriminatedUnionOption".
How can I achieve the desired behaivior in validation?
Here is a codesanbox of my problem: https://codesandbox.io/s/zod-refine-in-discriminated-union-5kve15
Upvotes: 7
Views: 8418
Reputation: 554
The solution is to refine the discriminated union itself, not the option inside the union:
const schema = z.discriminatedUnion('option', [
z.object({ option: z.literal(Option.FULL) }),
z.object({
option: z.literal(Option.TIME_PERIOD),
from: z.date(),
to: z.date(),
}),
z.object({ option: z.literal(Option.MONTH), month: z.date() }),
]).refine(
(data) => {
if (data.option === Option.TIME_PERIOD) {
return isBefore(data.from, data.to)
}
return true
},
{
message: '"from" must be before "to"',
path: ['from'],
}
)
Upvotes: 13