eduardweb.
TypeScript avansatAvansat#typescript#type-safety#webdev#rbac

Cum scapi de string-uri magice în RBAC cu Template Literal Types în TypeScript

De Dan Ciobanu, 25 iul. 2026 · 10 vizualizări · 2 like-uri

Postat 25 iul. 2026
typescript
type Resource = 'users' | 'billing' | 'reports';
type Action = 'read' | 'write' | 'delete';
type Scope = 'own' | 'global';

// Generăm automat toate combinațiile valide
type Permission = `api:${Resource}:${Action}:${Scope}`;

function checkPermission(permission: Permission): boolean {
  // Logică de verificare la runtime
  return true;
}

// OK - Autocomplete funcționează perfect
checkPermission('api:users:read:own');
checkPermission('api:billing:write:global');

// Eroare la compilare: Type 'api:users:update:own' is not assignable...
// checkPermission('api:users:update:own');

Acum vreo doi ani am refăcut modulul de autorizare pentru o aplicație SaaS unde aveam peste 140 de permisiuni împrăștiate prin tot codul. Peste tot aveam string-uri hardcodate pentru verificări de acces. Problema era că un coleg scria api:users:read, altul scria api:user:read la singular, iar un altul uita vreun separator și scria api:usersRead.

Evident, bugs în producție. Verificările picau silențios pentru că un if (user.hasPermission('api:user:read')) returna mereu false. Soluția clasică ar fi fost un enum uriaș sau un obiect const imens, dar e rigid și greoi de întreținut.

Aici vin mănușă Template Literal Types, o opțiune introdusă prin TypeScript 4.1 pe care încă o văd prea puțin folosită la potențialul ei maxim.

Cum construiești tipul din bucăți

Ideea e simplă: folosești sintaxa de template string din JavaScript, dar direct în definirea tipurilor. Declarăm mai întâi entitățile de bază (resursele și acțiunile), iar TypeScript va genera automat produsul cartezian al tuturor combinațiilor valide.

Dacă ai 4 resurse și 3 acțiuni, TypeScript va genera automat un union de 12 tipuri de string-uri valide. Fără să scrii manual fiecare variantă și fără să rătăcești vreo combinație.

Auto-complete în IDE și transformări

Câștigul cel mai mare pe Developer Experience nu e doar că-ți crapă build-ul când greșești un caracter. Când apelezi funcția de verificare a permisiunilor în VS Code, deschizi ghilimelele, apăși Ctrl + Space și IDE-ul îți oferă autocompletion exact pe string-urile valide construite din tipul tău.

Mai mult, poți folosi tipuri utilitare native din TypeScript precum Capitalize, Uppercase sau Lowercase. Dacă backend-ul tău se așteaptă ca acțiunea să fie scrisă cu majuscule (de exemplu api:users:READ), poți aplica Uppercase<Action> direct în definiție, fără să faci conversii la runtime.

Trade-off-ul real: Performanța compilatorului

Să fim sinceri, există și un dezavantaj major dacă exagerezi. Produsul cartezian poate scăpa rapid de sub control.

Dacă ai 15 resurse, 6 acțiuni, 4 scope-uri și 3 medii, un template literal de forma ${Env}:${Resource}:${Action}:${Scope} va genera peste 1.000 de combinații. La un proiect anterior, un coleg a încercat să pună 5 niveluri de dinamism într-un singur tip. Rezultatul? Language server-ul de TypeScript din VS Code a început să mănânce 4GB RAM, autocompletion-ul avea o întârziere de 3 secunde, iar build-ul final a devenit sensibil mai lent.

Regula mea de aur: dacă uniunea rezultată depășește 300-400 de variante, regândește structura. Nu lăsa TypeScript să genereze combinații pe care nu le folosești niciodată în aplicație.

Voi cum gestionați permisiunile type-safe între frontend și backend? Mergeți pe generare automată din scheme (OpenAPI/Prisma) sau le definiți manual în TS?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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