eduardweb.
TypeScriptÎncepător#typescript#frontend#backend#programming

TypeScript Utility Types în producție: Cum să nu mai duplici interfețe

De Bogdan Răducanu, 1 iul. 2026 · 18 vizualizări · 2 like-uri

Postat 1 iul. 2026
typescript
interface DbUser {
  id: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
  role: 'admin' | 'user';
}

// Safe approach: selectăm doar ce are voie publicul să vadă
type PublicUserProfile = Pick<DbUser, 'id' | 'email' | 'role'>;

// Pentru update (PATCH): toate devin opționale, dar nu trimitem ID-ul sau parola
type UpdateUserPayload = Partial<Omit<DbUser, 'id' | 'passwordHash' | 'createdAt'>>;

const updateMyUser = (id: string, data: UpdateUserPayload) => {
  // data poate fi { email: "nou@email.com" }
};

Salutare! Astăzi vreau să vorbim despre cum evităm duplicarea de cod în TypeScript folosind Utility Types. Am văzut prea des proiecte unde aceeași entitate are cinci variante scrise manual, o rețetă sigură pentru bug-uri când se schimbă ceva în baza de date.

La un proiect cu vreo 12k useri activi, aveam o tabelă de User cu peste 20 de câmpuri, de la detalii de facturare până la hash-ul parolei și timestamps. Când a trebuit să facem fluxurile de editare profil, creare user și vizualizare publică, codul devenise o ciorbă de UserUpdateInput, UserCreateInput și UserPublicResponse. Atunci am zis stop și am trecut totul pe utility types.

Pick și Omit: Opt-in vs Opt-out

Cele mai folosite sunt, evident, Pick și Omit. Ele te lasă să creezi tipuri noi pornind de la o interfață existentă, fie alegând doar ce ai nevoie, fie eliminând ce e sensibil.

Aici e un trade-off major de securitate despre care nu vorbește multă lume. La început, foloseam Omit ca să scot parola când trimiteam userul spre front-end. E rapid, dar e periculos. Am pățit ca un coleg să adauge un câmp nou și sensibil în baza de date (de exemplu, isAdmin), iar acel câmp s-a scurs direct pe client pentru că Omit nu îl avea pe lista neagră.

De atunci, regula mea e simplă: folosesc Pick pentru API-uri publice (opt-in explicit pentru ce trimit) și Omit doar pe plan intern sau în teste, unde riscurile sunt minime.

Partial și Required la update-uri

Când faci un endpoint de tip PATCH pentru update, clientul trimite doar câmpurile pe care vrea să le schimbe. Aici intervine Partial, care face toate proprietățile opționale.

Partea nasoală? Partial e prea permisiv. Îți permite să trimiți un obiect complet gol {} și TypeScript nu va zice nimic. Dacă ai nevoie ca măcar un câmp să fie prezent, trebuie să scrii o validare custom la runtime sau un tip utilitar ceva mai complex.

La polul opus, Required e util când iei date dintr-o bază de date unde unele coloane sunt nullable, dar în logica ta de business ești absolut sigur că acele date au fost deja completate la pașii anteriori ai formularului.

ReturnType: Când nu controlezi tu codul

Pe acesta îl folosesc masiv când lucrez cu librării externe sau când am funcții generatoare complexe (factory functions). În loc să scriu manual interfața pentru ce returnează o funcție terță, las TypeScript să o deducă singur.

Am economisit cam 30% la timpul de scriere a tipurilor într-o aplicație Next.js doar extragând automat tipurile de return din funcțiile de fetch din backend direct în componentele de pe frontend.

Concluzia mea

Utility types sunt geniale, dar am văzut și cod scris de developeri pasionați care arăta ca o ecuație de gradul trei: ReturnType<typeof func>[number]['data']. Când codul devine greu de citit, oprește-te. Uneori, o interfață nouă, simplă și curată, e de zece ori mai bună decât una derivată prin șapte metode.

Voi ce folosiți cel mai des? Vă asumați riscul cu Omit sau mergeți la sigur cu Pick?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.