# 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.

> Pagina: https://ui.eneawork.it/blog/zod-validazione-form
> Markdown: https://ui.eneawork.it/blog/zod-validazione-form.md

*2026-11-01*

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.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, letto da /api/stats, e zod 4.6.7 dichiara 6.148.944 byte non compressi nel registro npm, misurati entrambi il 1 novembre 2026. Il conteggio del catalogo viene da una query all’endpoint, la dimensione dal campo dist.unpackedSize: nessuno dei due dice quanto codice arriva al browser dopo il bundle.

## 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.

## Record vivi nel catalogo

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.

## FAQ

### 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.
