eduardweb.
TypeScript avansatAvansat#typescript#type-safety#dx#typescript-advanced

Template Literal Types: Cum scapi de string-uri magice la permisiuni

De Cristian Barbu, 13 iun. 2026 · 18 vizualizări · 3 like-uri

Postat 13 iun. 2026
typescript
type Resource = 'user' | 'document' | 'billing';
type Action = 'create' | 'read' | 'update' | 'delete';

// Generăm automat tipuri de forma 'api:user:create'
type Permission = `api:${Resource}:${Action}`;

function checkPermission(userPerms: Permission[], required: Permission): boolean {
  return userPerms.includes(required);
}

// Exemplu de utilizare corectă:
const myPermissions: Permission[] = ['api:user:read', 'api:document:create'];
checkPermission(myPermissions, 'api:user:read'); // Compiles fine!

// @ts-expect-error - Va da eroare de compilare: Typo la resursă
checkPermission(myPermissions, 'api:users:read');

Am avut recent de refăcut modulul de autorizare pentru o platformă SaaS destul de mărișoară, cu vreo 120 de endpoint-uri active și roluri dinamice. Înainte foloseam string-uri simple pentru permisiuni și ne loveam constant de typo-uri subtile care treceau de teste și ajungeau direct în producție. Soluția care ne-a salvat a fost trecerea la template literal types în TypeScript, o funcționalitate care sună academic, dar rezolvă o problemă extrem de practică.

Dacă vrei să scapi definitiv de erori de tipul api:usr:create în loc de api:user:create, merită să arunci o privire pe abordarea asta. Am economisit timp prețios la debugging și am eliminat o întreagă clasă de bug-uri stupide.

De ce string-urile simple sunt o bombă cu ceas

Să fim sinceri, clasicul tip type Permission = string e o invitație la dezastru în aplicații mari. Am pățit ca un coleg (sau chiar eu, într-o zi de vineri la ora 17) să scrie greșit o permisiune într-un helper de UI. Codul compila fără nicio avertizare, dar clientul primea un ecran gol în producție din cauza unui simplu caracter lipsă.

În trecut, foloseam obiecte mari de tip as const sau enum-uri rigide. Funcționa, dar codul devenea incredibil de verbos și greu de întreținut când adăugam resurse noi în aplicație. Cu template literal types, practic îi spui compilatorului regulile de sintaxă, iar el generează automat toate variantele valide.

Cum construim tipurile în mod inteligent

Ideea de bază e să definim separat resursele sistemului și acțiunile posibile ca union types, iar apoi să le concatenăm direct în tipul final.

Partea cea mai mișto la abordarea asta este experiența de dezvoltare (DX). Autocomplete-ul în IDE funcționează impecabil. Când începi să scrii argumentul pentru o funcție de verificare, editorul îți va sugera exact combinațiile valide. Nu mai trebuie să stai cu documentația deschisă sau să dai copy-paste din alte fișiere ca să fii sigur că ai scris corect permisiunea.

Trade-off-ul de care nu-ți zice nimeni: Performanța compilatorului

Arată extrem de elegant, dar vine cu un cost destul de serios dacă exagerezi. Fiecare combinație pe care o permiți adaugă tipuri noi în memoria compilatorului.

La un proiect cu peste 8k de utilizatori activi și un panou de admin complex, am vrut inițial să fiu „prea deștept”. Am încercat să generez tipuri de genul ${Tenant}:${Role}:${Resource}:${Action}. Având vreo 5 roluri, 50 de resurse și 6 acțiuni posibile, TypeScript trebuia să evalueze și să țină în memorie mii de variante. Rezultatul? Build-ul în CI/CD a crescut cu vreo 30% ca timp de rulare, iar serverul de TS din VS Code crash-uia o dată la câteva ore.

Am învățat atunci o lecție importantă: țineți structura de template literals cât mai plată posibil. Dacă aveți nevoie de dinamică mai mare, lăsați anumite segmente ca string simplu sau împărțiți tipurile pe module mai mici.

Voi cum gestionați permisiunile în proiectele mari de TypeScript? Mergeți pe varianta asta ultra-strictă sau preferați să le lăsați la nivel de string-uri dinamice și să vă bazați doar pe teste?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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