reactjs - zod betinget validering basert på skjema felt


Jeg har et status='DRAFT' | 'READY' enum-felt i skjemaet mitt, er det mulig å endre validering i zod-biblioteket basert på verdien av dette feltet?

// validation passed
{
  name: "John",
  surname: null,
  status: "DRAFT"
}

// validation failed
{
  name: "John",
  surname: null,
  status: "READY"
}

Så i praksis, hvis status === "READY", fjern .min(1) herfra

const schema = z.object({
  name: z.string(),
  surname: z.string().min(1),
  status: z.enum(["READY", "DRAFT"])
});

Svar #1

Svaret du kom opp med ved å bruke unioner er mulig. Et alternativ som kan gi bedre typer i fremtiden, er å dra nytte av zods discriminatedUnion-skjema:

// placing shared fields in one place to avoid repetition
const base = z.object({
  name: z.string(),
});

const schema = z.discriminatedUnion(
  'status',
  [
    z.object({
      status: z.literal("DRAFT"),
      surname: z.string(),
    }).merge(base),
    z.object({
      status: z.literal("READY"),
      surname: z.string().min(1),
    }).merge(base),
  ],
);

I dette tilfellet tror jeg at du vil ende opp med de samme utledede typene som du ville gjort ved å bruke union direkte, men denne tilnærmingen er litt mer motstandsdyktig mot andre endringer du kanskje vil skille mellom. For eksempel, hvis DRAFT-objektet tillot at surname var valgfritt, ville bruk av den diskriminerte unionen bety at du kunne raffinere til ikke-valgfrie typer hvis status er "READY".

Med union-definisjonen vil typen for surname i det eksempelet alltid være string | undefined uavhengig av verdien til status.

Svar #2

Dette fungerer

const schema = z.union([
  z.object({
    name: z.string(),
    surname: z.string(),
    status: z.literal("DRAFT"),
  }),
  z.object({
    name: z.string(),
    surname: z.string().min(1),
    status: z.literal("READY"),
  }),
]);

Relaterte artikler