Zod Discriminated Union Form Router
Model variant form payloads with Zod discriminated unions, routing each discriminant to its own schema, fields, and submit handler.
Code
import { z } from 'zod';
const emailLogin = z.object({
method: z.literal('email'),
email: z.string().email(),
password: z.string().min(8),
remember: z.boolean().default(false),
});
const smsLogin = z.object({
method: z.literal('sms'),
phone: z.string().regex(/^\+\d{7,15}$/),
code: z.string().regex(/^\d{6}$/),
});
const oauthLogin = z.object({
method: z.literal('oauth'),
provider: z.enum(['github', 'google']),
idToken: z.string().min(20),
});
const LoginPayload = z.discriminatedUnion('method', [
emailLogin, smsLogin, oauthLogin,
]);
type LoginPayload = z.infer<typeof LoginPayload>;
const handlers: Record<LoginPayload['method'], (p: never) => string> = {
email: (p) => 'signing in with ' + (p as z.infer<typeof emailLogin>).email,
sms: (p) => 'verifying sms for ' + (p as z.infer<typeof smsLogin>).phone,
oauth: (p) => 'oauth via ' + (p as z.infer<typeof oauthLogin>).provider,
};
function submit(raw: unknown): string {
const parsed = LoginPayload.parse(raw);
return handlers[parsed.method](parsed as never);
}
console.log(submit({ method: 'email', email: '[email protected]', password: 'hunter2xx' }));
console.log(submit({ method: 'sms', phone: '+8613800138000', code: '123456' }));Report a problem with this exampleOpens a pre-filled issue on GitHub.