React

Validazione con Zod

Zod valida un oggetto a runtime e ne ricava il tipo TypeScript: uno schema, errori per campo e un tipo che non può divergere dalla regola.

In sintesi

  • Lo schema Zod è l’unica fonte della regola e del tipo.
  • safeParse restituisce un risultato invece di lanciare.
  • fieldErrors è già una mappa per campo, pronta per l’interfaccia.
  • Lo stesso schema va rieseguito sul server.

Zod valida un oggetto a runtime e ne ricava il tipo TypeScript: dichiari lo schema una volta e ottieni errori per campo e un tipo che non può divergere dalla regola.

Lo schema è il contratto

Uno schema Zod descrive forma e regole di un oggetto, e z.infer estrae il tipo corrispondente: la regola e il tipo vengono dalla stessa riga, quindi non possono divergere dopo una modifica.

import { z } from "zod";

export const signupSchema = z.object({
  email: z.email(),
  password: z.string().min(12),
  age: z.coerce.number().int().min(18),
});

export type SignupValues = z.infer;

Leggere gli errori per campo

const parsed = signupSchema.safeParse({ email: "nope", password: "short", age: "17" });

if (!parsed.success) {
  const errors = parsed.error.flatten().fieldErrors;
  // { email: ["Invalid email"], password: [...], age: [...] }
}

safeParse non lancia: restituisce un risultato con success e, in caso di errore, una mappa per campo. Quella mappa è già pronta per l’interfaccia, perché ogni chiave corrisponde a un input.

Lo stesso schema sul server

const body: unknown = await request.json();
const parsed = signupSchema.safeParse(body);

if (!parsed.success) {
  return Response.json({ errors: parsed.error.flatten() }, { status: 400 });
}

La validazione nel browser è una comodità, non un controllo: una richiesta costruita a mano la salta. Lo stesso schema va rieseguito sul server, dove il dato entra davvero nel sistema.

Il comando

npm install zod
npx tsc --noEmit

Zod è distribuito con licenza MIT; il secondo comando controlla che il tipo dedotto dallo schema compili senza errori nel progetto.

Tre record mostrano la stessa idea di campo con errore associato: credit-card-form, login-form e la categoria blocchi form, dove ogni blocco ha già gli stati di errore.

La limitazione

Uno schema controlla la forma, non la verità: un indirizzo email sintatticamente valido può non esistere, e un’età di 18 anni non prova nulla. Unicità, permessi ed esistenza del dato restano al database.

Dove continuare

Chi possiede il valore di un campo è in form controllati e non; la validazione lato server è in Server Actions e validazione; l’integrazione con il form è in react-hook-form con Zod; il confronto fra le librerie è in librerie di form React.

Domande frequenti

Zod valida a runtime o solo in TypeScript?

A runtime. Il tipo è una conseguenza: lo schema esegue il controllo sui valori reali e ne deduce il tipo TypeScript.

safeParse o parse?

safeParse quando l’errore è atteso e va mostrato all’utente; parse quando un valore non valido è un bug e deve fermare l’esecuzione.

Posso usare lo stesso schema sul server?

Sì, ed è il punto: lo stesso oggetto schema gira in Node e nel browser, quindi la regola non viene duplicata.

Zod sostituisce la validazione HTML?

No. Gli attributi del browser danno un riscontro immediato senza JavaScript; Zod aggiunge regole che l’HTML non sa esprimere.

Perché zod pesa così tanto su npm?

Perché il pacchetto pubblicato contiene tutte le build, le lingue e i tipi. Al browser arriva solo la parte importata, dopo il tree shaking.