reactjs - Använder formulärvalidatorn ZOD:s discriminatedUnion()-funktion för att skilja mellan 3 formulär


ValidationSchema = z.object({
AuthenticationBlock: z.object({
  ChoiceOfForm: z.enum()
  DataBlock: z.discriminatedUnion(ChoiceOfForm, [
     z.object({ ChoiceOfForm = 1, empty fields}) //corresponds to the basic form
     z.object({ ChoiceOfForm = 2, just username/pw fields) //corresponds to less basic form
     z.object({ ChoiceOfForm = 3, user/pw + many fields}) //corresponds to advanced form
    ])
  })
})

Exempel på ett objekt:

export type AuthenticationFormValues = {
    AuthenticationBlock?: {
        choice?: AuthenticationFormChoice | undefined;
        data: {
            password?: string;
            username?: string;
            formAuthenticationConfig?: {
                formUrl?: string;
                javaScriptLoadingDelayInMilliseconds?: number;
                forceLogin?: boolean;
                customLoginSequence?: string;
                authenticationFailed?: FormAuthenticationFailedConfiguration;
            };
        };
    };
};

choiceOfForm är ett ENUM som motsvarar 3 radioknappar som kollapsar olika formulär (1, 2 eller 3). Jag skulle vilja använda ZOD:s discriminatedUnion()-funktion för att möjliggöra korrekt formulärvalideringsblock beroende på vilken choiceOfForm som är vald (1, 2 eller 3). Finns det ett sätt att skicka choiceOfForm-variabeln till discriminatedUnion(choiceOfForm, ...) för att göra detta?

Tack

Svar #1

Jag tror att du kan uppnå det du letar efter med något som:

import { z } from "zod";

enum ChoiceOfForm {
  Option1 = 1,
  Option2 = 2,
  Option3 = 3
}

// Defining this once since it's shared between two of the arms.
const PasswordFields = z.object({
  password: z.string(),
  email: z.string().email()
});

const schema = z.discriminatedUnion("choice", [
  z.object({
    choice: z.literal(undefined),
  }),
  z.object({
    choice: z.literal(ChoiceOfForm.Option1)
  }),
  z.object({
    choice: z.literal(ChoiceOfForm.Option2)
  }).merge(PasswordFields),
  z.object({
    choice: z.literal(ChoiceOfForm.Option3),
    extraOption: z.number()
  }).merge(PasswordFields)
]);

Zods discriminatedUnion-funktion tar nyckeln som du kommer att diskriminera på som det första argumentet och en lista över scheman för varje "gren" av unionen. Observera att nästan vilket objekt som helst kommer att tolkas framgångsrikt med detta schema på grund av alternativet z.literal(undefined). Du kanske vill utelämna det som en möjlighet, men jag är inte säker på dina affärskrav.

Om du lyckas parsa något med detta schema kan du kontrollera värdet av choice med ett switch eller if-uttryck och begränsa typerna precis som du skulle göra med en vanlig diskriminerad union.