eduardweb.
TypeScript avansatAvansat#architecture#typescript#type-safety

Template literal types: Cum scapi de string-urile chioare în permisiuni

De Vlad Stancu, 6 iun. 2026 · 1 vizualizări · 2 like-uri

Postat acum 3 zile
typescript
type Resource = 'user' | 'billing' | 'project';
type Action = 'create' | 'read' | 'update' | 'delete';

// Ce facem dacă 'billing' nu poate fi ștearsă niciodată?
type InvalidPermissions = 'api:billing:delete';

type Permission = Exclude<`api:${Resource}:${Action}`, InvalidPermissions>;

function hasAccess(perm: Permission) {
  // Logică internă
  return true;
}

// 👍 Compiles fine
hasAccess('api:user:delete');

// ❌ TS Error: Argument of type '"api:billing:delete"' is not assignable...
// hasAccess('api:billing:delete');

Am decis să scriu despre asta după ce am curățat un codebase unde permisiunile erau doar niște string-uri chioare aruncate peste tot. Dacă ai scris vreodată api:users:write în loc de api:user:write și ai aflat asta doar în producție, template literal types o să-ți salveze mult timp. Am pățit asta pe un proiect cu vreo 8k utilizatori activi, unde un simplu typo la o permisiune de facturare a blocat checkout-ul timp de două ore.

În mod clasic, lumea folosește enums sau uniuni simple de string-uri pentru permisiuni. Dar când ai o structură ierarhică de tipul sistem:resursă:acțiune, lucrurile devin repetitive și greu de întreținut.

Magia din spatele template literals

TypeScript ne permite să combinăm tipuri de tip string exact ca în template literals din JavaScript. Putem defini separat resursele și acțiunile, iar TS va genera automat toate combinațiile posibile la nivel de tip.

Partea mișto e că funcționează exact ca o înmulțire carteziană. Dacă ai 3 resurse și 4 acțiuni, TypeScript generează automat cele 12 tipuri de string-uri valide. IDE-ul îți va oferi autocompletion instant când începi să scrii api:. Dacă pui un caracter greșit, compilatorul începe să urle înainte să apuci să dai commit.

Cum filtrăm combinațiile invalide?

Aici intervine adevărata utilitate a TS-ului avansat. Ce facem dacă anumite combinații pur și simplu nu au sens în lumea reală? De exemplu, poate nu vrei să permiți niciodată ștergerea resursei de billing direct din API.

Folosind utilitarul Exclude, putem scoate din tipul final exact acele string-uri care reprezintă acțiuni interzise din punct de vedere business. Compilatorul devine astfel gardianul regulilor tale de business.

Trade-off-ul sincer: Atenție la build time

Sună perfect, nu? Ei bine, există un cost destul de mare de care te lovești la proiecte mari. Am avut cazul la un monorepo unde aveam peste 50 de resurse și vreo 8 acțiuni posibile. În total, peste 400 de combinații.

TypeScript trebuie să evalueze și să țină în memorie fiecare combinație în parte. Când am început să adăugăm și roluri dinamice peste aceste tipuri, timpul de build în CI/CD a crescut cu aproape 30%. Compilatorul pur și simplu gâfâia încercând să rezolve tipurile recursive combinate cu template literals.

Dacă ai un set uriaș de permisiuni, s-ar putea ca această abordare să fie prea costisitoare pentru build-uri. În acel scenariu, e mai sănătos să folosești namespaces sau să împarți permisiunile pe module mai mici, în loc să ai un singur tip global gigantic.

Tu cum gestionezi permisiunile în aplicațiile mari? Mergi pe type safety strict la nivel de compilare sau lași validarea asta exclusiv în seama runtime-ului?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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