eduardweb.
TypeScriptÎncepător#typescript#best-practices#web-dev

Utility types în TypeScript: Cum să nu mai scrii interfețe duplicate degeaba

De Vlad Stancu, 23 apr. 2026 · 4 vizualizări · 3 like-uri

Postat acum 5 zile
typescript
interface User {
  id: string;
  name: string;
  email: string;
  avatarUrl: string;
  createdAt: Date;
}

// Folosim Pick pentru profilul public
type UserProfile = Pick<User, 'name' | 'avatarUrl'>;

// Folosim Omit pentru a crea un user nou (fără ID și dată)
type CreateUserDTO = Omit<User, 'id' | 'createdAt'>;

// Folosim Partial pentru update (doar câteva câmpuri)
type UpdateUserDTO = Partial<CreateUserDTO>;

M-am lovit prima dată serios de Utility Types acum vreo 5 ani, pe un proiect de fintech unde aveam o entitate de User imensă. Avea vreo 40 de câmpuri, de la date personale până la setări de KYC și istoric tranzacții. Problema? Aveam nevoie de versiuni diferite ale acestui obiect în vreo 10 locuri: la login, la profil, la admin, la update-ul de email.

Dacă ești la început, tentația e să faci copy-paste și să creezi UserUpdateInput, UserPublicProfile, UserAdminView. E cea mai sigură cale spre burnout tehnic. Schimbi un string în number la un câmp și trebuie să vânezi manual 12 fișiere. Am pierdut o zi întreagă odată pentru că am uitat să actualizez tipul unei adrese într-un DTO duplicat.

Pick și Omit – Chirurgie pe interfețe

La proiectul de care ziceam, am economisit cam 20% din liniile de cod doar trecând pe Pick și Omit. Pick e genial când ai un obiect mare, dar în UI vrei să afișezi doar numele și avatarul. Decât să definești o interfață nouă, mai bine extragi ce ai nevoie direct din sursa adevărului.

Omit e inversul lui. Îl folosesc des când primesc date de la API care includ și un id sau un createdAt, dar la un formular de "Create" nu am nevoie de ele. Totuși, mare atenție: dacă adaugi un câmp nou în interfața de bază, Omit s-ar putea să-l "scape" spre UI chiar dacă nu e gata să-l proceseze. E un trade-off între viteză și siguranță totală. Uneori e mai safe să fii explicit cu Pick decât să excluzi cu Omit și să te trezești cu date sensibile trimise în client.

Partial și Required – Dilema formularelor

Aici am avut cele mai multe bug-uri de logică. Partial<T> transformă toate proprietățile în opționale. E perfect pentru request-urile de tip PATCH. Ai un user cu 20 de câmpuri, dar el vrea să schimbe doar parola. Partial<User> rezolvă asta instant.

Partea proastă? Dacă abuzezi de Partial în logica de business, te trezești cu undefined peste tot și trebuie să pui optional chaining (?.) până te doare mâna. Am pățit-o la un script de migrare unde am folosit Partial dintr-o lene excesivă și am ajuns să crăpăm în producție pentru că lipsea un câmp critic pe care TypeScript nu l-a mai cerut. Dacă ai nevoie de ceva obligatoriu, Required e acolo să te salveze, deși recunosc că îl folosesc mult mai rar, cam în 5% din cazuri.

ReturnType – Când nu stăpânești tu librăria

Asta e "bijuteria" pentru momentele când folosești librării externe care nu exportă toate tipurile de care ai nevoie. Să zicem că ai o funcție complexă de tip factory care returnează un obiect masiv. Decât să încerci să deduci tu tipul ăluia manual, pui un ReturnType<typeof functiaMea> și ai scăpat. Am folosit asta masiv la un setup de Redux ca să scot tipul pentru RootState fără să-l scriu de mână la fiecare schimbare de slice.

În final, secretul e să nu te complici. Am văzut cod unde aveam Pick<Partial<Omit<T, 'a'>>, 'b'>. E oribil de citit. Dacă ai ajuns la trei niveluri de utility types imbricate, mai bine fă o interfață nouă și gata. Codul e pentru oameni, nu doar pentru compilator.

Voi ce folosiți cel mai des? Vă aruncați la Pick sau preferați să scrieți interfețe separate pentru claritate?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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