Siguranță End-to-End la Runtime: Integrarea TypeScript cu Zod și tRPC în TypeScript

Verificare, medii și unelte TypeScript 4.5+ & Zod 3.x

Ghid complet pentru validarea datelor la granițele sistemului: depășirea limitelor Type Erasure folosind Zod, inferența automată a tipurilor cu z.infer și arhitectura End-to-End Type Safety cu tRPC.

Sintaxă
const UserSchema = z.object({ id: z.number(), email: z.string().email() }); type User = z.infer<typeof UserSchema>;

Cea mai mare greșeală comisă în aplicațiile TypeScript este presupunerea că tipurile oferă siguranță asupra datelor primite din exterior. Din cauza mecanismului de Type Erasure, scrierea unui cod de forma:

const response = await fetch('/api/utilizator');
const user = await response.json() as User; // MINCIUNĂ PERICULOASĂ!

nu face nicio verificare reală la rulare! Dacă API-ul backend returnează o eroare 500 sub formă de HTML sau lipsește o proprietate critică, TypeScript nu va sesiza nimic, iar aplicația va crăpa câteva linii mai jos. Zod elimină această breșă prin combinarea validării de runtime cu inferența automată a tipurilor statice.

Definirea unei Scheme Zod și Inferența Automată de Tip
import { z } from 'zod';

// 1. Definim schema de validare la runtime:
export const UtilizatorSchema = z.object({
    id: z.number().int().positive(),
    nume: z.string().min(2, "Numele este prea scurt"),
    email: z.string().email("Format email invalid"),
    varsta: z.number().min(18).optional(),
    rol: z.enum(['admin', 'editor', 'client']).default('client'),
    created_at: z.coerce.date() // Transformă automat string-ul ISO în instanță Date!
});

// 2. MAGIA: Nu mai scriem o interfață manuală! O deducem direct din schemă:
export type Utilizator = z.infer<typeof UtilizatorSchema>;
// TypeScript generează automat tipul identic cu schema:
// { id: number; nume: string; email: string; varsta?: number | undefined; rol: "admin" | "editor" | "client"; created_at: Date; }

Parsare Sigură: safeParse vs parse

Metodă Comportament la Succes Comportament la Eroare Caz Recomandat
schema.parse(date) Returnează datele validate și transformate. Aruncă excepție ZodError. Middleware-uri unde erorile sunt prinse într-un errorHandler global.
schema.safeParse(date) Returnează { success: true, data: T } Returnează { success: false, error: ZodError } (fără throw!) Validare formulare React/Vue, endpoints de API REST, webhook-uri.
Validarea datelor primite dintr-un request extern
async function incarcaDateClient(jsonBrut: unknown) {
    const rezultat = UtilizatorSchema.safeParse(jsonBrut);
    
    if (!rezultat.success) {
        // Obținem erorile structurate pe câmpuri pentru afișare în UI:
        console.error("Validare eșuată:", rezultat.error.flatten().fieldErrors);
        return null;
    }
    
    // rezultat.data este 100% sigur și tipat complet ca 'Utilizator':
    console.log(`Utilizator validat: ${rezultat.data.nume}`);
    return rezultat.data;
}

Conceptul de End-to-End Type Safety (tRPC)

Într-o arhitectură modernă tRPC sau Hono OpenAPI, schemele Zod din backend sunt exportate ca tipuri directe către frontend. Când un dezvoltator modifică tipul unei coloane sau adaugă un câmp obligatoriu în backend, proiectul de frontend nu mai compilează în editor până când apelul nu este actualizat corespunzător! Aceasta elimină definitiv erorile de desincronizare între frontend și backend.