eduardweb.
TypeScriptÎncepător#typescript#frontend#clean-code#webdev

Utility types în practică: Cum să nu mai scrii tipuri la indigo

De Adrian Voicu, 10 iun. 2026 · 20 vizualizări · 2 like-uri

Postat 10 iun. 2026
typescript
interface User {
  id: string;
  name: string;
  email: string;
  passwordHash: string;
  role: 'admin' | 'user';
  createdAt: Date;
}

// Alegem doar ce vrem să afișăm public
type PublicProfile = Pick<User, 'id' | 'name' | 'role'>;

// Scoatem parolele din datele de formular
type UserFormData = Omit<User, 'passwordHash' | 'createdAt'>;

// Pentru PATCH requests, toate devin opționale
type UpdateUserPayload = Partial<UserFormData>;

// Extrage tipul returnat de o funcție de configurare
const fetchConfig = () => ({ timeout: 5000, retries: 3, debug: false });
type AppConfig = ReturnType<typeof fetchConfig>;

De la duplicate inutile la cod curat

Am văzut prea mulți devi, chiar și cu ceva experiență, care își scriu de mână câte o interfață nouă pentru fiecare variație a unui model din baza de date. TypeScript are niște utilitare geniale (utility types) încorporate care îți salvează ore de refactoring și mii de linii de cod duplicat. Hai să vedem cum le folosesc eu în producție ca să nu-mi prind urechile când se schimbă structura unui API.

La un proiect trecut cu vreo 15.000 de utilizatori activi, aveam o tabelă de User uriașă în Postgres, mapată direct în backend. În frontend, evident, nu voiam să trimit hash-ul de parolă sau flag-urile interne de admin. Soluția clasică a unui junior e să facă o interfață nouă UserFrontend și să copieze câmpurile. Greșit. Când adaugi un câmp nou în bază, trebuie să-ți aduci aminte să actualizezi manual și interfața aia.

Pick și Omit în viața de zi cu zi

Aici intervin Pick și Omit. Sunt exact ce le spune numele. Cu Pick alegi doar ce te interesează dintr-un tip existent. Cu Omit excluzi ce e sensibil sau nefolositor.

Eu prefer Pick când am nevoie de un subset mic de date (de exemplu, doar id și name pentru un dropdown). Dacă am o entitate mare și vreau să scap doar de o cheie-două, merg pe Omit.

Trade-off-ul sincer? Omit e un pic periculos. Dacă redenumești un câmp în tipul de bază, s-ar putea ca Omit să nu dea eroare de compilare imediat dacă tipul rezultat e folosit într-un mod mai permisiv. Personal, prefer să fiu explicit cu Pick chiar dacă scriu mai multe chei, e mai safe la refactoring masiv.

Partial și Required pentru request-uri de API

Când scrii un endpoint de tip PATCH pentru update, clientul nu-ți trimite tot obiectul, ci doar bucățica pe care o modifică. Aici Partial<T> e rege. Îți transformă toate proprietățile în opționale (?).

Dar am pățit o fază stupidă: aveam un config de sistem unde toate câmpurile trebuiau să fie completate la inițializare, dar în cod aveam un obiect parțial configurat de un tool de build. Am folosit Required<T> ca să forțez ca, după faza de setup, totul să fie complet.

Mare atenție: Partial aplicat pe un tip foarte imbricat (nested) nu e recursiv. Modifică doar proprietățile de la primul nivel. Pentru chestii adânci, ai nevoie de un tip custom DeepPartial, dar de cele mai multe ori e overkill.

ReturnType: Când îți e lene să scrii interfețe pentru funcții

Am avut de integrat un SDK extern scris destul de prost, fără tipuri exportate pentru rezultatele funcțiilor, dar funcțiile în sine erau bine scrise și returnau obiecte complexe. În loc să stau să ghicesc și să scriu manual o interfață cu 30 de câmpuri pentru ce returna o funcție de acolo, am folosit ReturnType<typeof sdkMethod>.

TypeScript a dedus singur totul din implementarea funcției externe. Am economisit cred că o zi întreagă de mapat manual și am evitat erorile umane de scriere.

Voi ce abordare aveți? Mergeți pe tipuri derivate cu utilitare sau preferați să scrieți interfețe separate pentru fiecare payload ca să fie mai ușor de citit codul la o primă vedere?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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