webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Unelte
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Formulare
  12. 12Date și backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animații
  16. 16Testare
  17. 17Arhitectură
Formulare · Lecția 3 din 4

Validare cu Zod

Scheme, safeParse, coerce pentru FormData, erori per câmp, o schemă pe client și server.

Actualizat

Ce este validarea cu o schemă

Datele care intră în aplicație (formulare, query params, răspunsuri de API, JSON) sunt de tip „nu știu ce e” — unknown. Validarea verifică dacă au forma și regulile așteptate înainte să le folosești.

O schemă descrie forma datelor o singură dată, ca un obiect. Din ea obții trei lucruri:

  1. validare la runtime (în browser și pe server);
  2. mesaje de eroare per câmp;
  3. tipul TypeScript, dedus automat — nu-l mai scrii de mână.

Zod e librăria standard pentru asta în ecosistemul TypeScript.

O schemă

import { z } from 'zod'

export const signupSchema = z.object({
  name: z.string().trim().min(2, 'Numele e prea scurt'),
  email: z.email('Email invalid'),
  age: z.coerce.number().int().min(16, 'Minim 16 ani'),
  password: z.string().min(8, 'Minim 8 caractere'),
  terms: z.literal('on', 'Trebuie să accepți termenii'),
})

export type SignupInput = z.infer<typeof signupSchema>
// { name: string; email: string; age: number; password: string; terms: 'on' }

Tipurile de bază — și ce rezolvă

Schemă Validează Notă
z.string(), z.number(), z.boolean() tipul
z.email(), z.url(), z.uuid() formate de string în Zod 4 sunt la nivel de top; z.string().email() e învechit
.min(), .max(), .regex() reguli primesc mesajul ca al doilea argument
.trim(), .toLowerCase() transformă valoarea rezultatul e deja curățat
z.coerce.number() convertește '42' → 42 înainte de validare esențial pentru FormData (totul e string)
z.enum(['admin', 'editor']) una din valori
.optional(), .nullable(), .default(x) valori lipsă
z.array(schema), z.object({...}) colecții, obiecte imbricate

parse vs safeParse

schema.parse(data) schema.safeParse(data)
Date valide returnează datele { success: true, data }
Date invalide aruncă ZodError { success: false, error } — nu aruncă
Când date care trebuie să fie corecte (config, env) — o eroare e un bug input de la user — erorile sunt normale
const result = signupSchema.safeParse(Object.fromEntries(formData))
if (!result.success) {
  return { errors: z.flattenError(result.error).fieldErrors }
  // { email: ['Email invalid'], age: ['Minim 16 ani'] }
}
await createUser(result.data)          // tipat, curățat, convertit
Formatare erori Rezultat Când
z.flattenError(error) { formErrors: [], fieldErrors: { email: [...] } } formulare simple (un nivel)
z.treeifyError(error) arbore care urmează forma schemei obiecte imbricate, liste

Reguli care implică mai multe câmpuri

const schema = z
  .object({ password: z.string().min(8), confirm: z.string() })
  .refine(d => d.password === d.confirm, { message: 'Parolele nu coincid', path: ['confirm'] })

path pune eroarea pe câmpul potrivit.

O schemă, două locuri

Cel mai mare avantaj: aceeași schemă pe client (feedback rapid în formular) și pe server (securitate).

  • src/
    • features/
      • signup/
        • model/
          • signup-schema.tsschema Zod + tipul dedus
        • ui/
          • signup-form.tsxuseForm({ resolver: zodResolver(signupSchema) })
        • api/
          • signup-action.ts'use server' → signupSchema.safeParse(...)

Validarea din client poate fi ocolită oricând. Cea de pe server e cea care contează.

Alternative

Librărie De ce ai alege-o
Zod standardul, ecosistem uriaș, tipuri excelente
Valibot API modular, bundle mult mai mic pentru client
ArkType sintaxă apropiată de TypeScript, foarte rapid

Toate trei implementează Standard Schema — librăriile de formulare le acceptă la fel.

Pe scurt

  • Schemă = validare + mesaje + tip TS, scrise o singură dată.
  • safeParse pentru input de la user; z.coerce pentru FormData; z.flattenError pentru erori per câmp.
  • Aceeași schemă în client și pe server; serverul decide.

Surse oficiale

Exerciții

Ți-a fost utilă pagina?

Un click — fără cont.