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

Cum am salvat un proiect cu 120 de rute folosind Template Literal Types în TypeScript

De Cristian Barbu, 12 iul. 2026 · 13 vizualizări · 3 like-uri

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

// Generăm automat tipul: "api:user:create" | "api:user:read" | ...
type Permission = `api:${Resource}:${Action}`;

interface User {
  id: string;
  permissions: Permission[];
}

function hasPermission(user: User, permission: Permission): boolean {
  return user.permissions.includes(permission);
}

const me: User = {
  id: "dev-42",
  permissions: ["api:user:read", "api:document:create"]
};

// OK
hasPermission(me, "api:document:create");

// Eroare de compilare direct în IDE:
// hasPermission(me, "api:user:write");

Am lucrat recent la un sistem de autorizare pentru o platformă SaaS cu vreo 120 de rute și roluri super granulare. Clasic, permisiunile erau string-uri chioare gen "user:write" sau "billing:view", împrăștiate prin zeci de componente React și endpoint-uri de backend. Am trecut totul pe template literal types în TypeScript și am eliminat complet bug-urile de tipar care ne mai scăpau în producție.

Problema cu string-urile "magice"

La început, echipa folosea un simplu tip string pentru permisiuni. Pare inofensiv când ai 5 rute, dar când ajungi la un proiect serios, lucrurile scapă de sub control. Un coleg scria "user:write", altul scria "users:write" (cu "s" la final), iar QA-ul ne dădea tichete că butonul de editare e dezactivat degeaba.

Am încercat inițial cu un enum uriaș. A fost un coșmar de mentenanță. De fiecare dată când adăugam o resursă nouă în baza de date, trebuia să actualizăm manual vreo trei fișiere diferite și să importăm enum-ul peste tot.

Cum ne salvează Template Literal Types

TypeScript ne permite să concatenăm tipuri de string-uri exact cum facem în JavaScript cu backticks. Definim seturile de bază și lăsăm compilatorul să facă toată treaba de multiplicare.

Practic, dacă am trei resurse și patru acțiuni posibile, prin definirea unui template literal type obținem automat toate cele 12 combinații posibile. Dacă cineva încearcă să folosească o permisiune invalidă, editorul urlă imediat, înainte să facem commit.

Am integrat asta într-o funcție simplă de verificare, hasPermission. TypeScript știe acum să ne ofere autocomplete pentru absolut orice combinație validă de resursă și acțiune direct în IDE. Am economisit cam 30% din timpul pe care îl pierdeam înainte scriind teste unitare doar ca să verificăm dacă string-urile de permisiuni sunt scrise corect.

Trade-off-ul de care nu-ți spune nimeni

Sună perfect, dar există o capcană majoră pe care am simțit-o pe pielea noastră: performanța compilatorului.

Template literal types generează o uniune (union type) în spate. Dacă ai 30 de resurse, 5 acțiuni și vrei să adaugi și un prefix de mediu sau un ID de tenant (de genul tenant:${string}:api:${Resource}:${Action}), TypeScript va genera mii de combinații. La un moment dat, pe un build de CI/CD, ne-am trezit cu eroarea TS2590: Expression produces a union type that is too complex. Ne-a crescut timpul de build cu vreo 40 de secunde până ne-am prins de unde era.

Regula mea de aur acum: folosiți template literals pentru structuri simple, de maximum 2-3 niveluri de adâncime. Dacă aveți nevoie de dinamică extremă, mai bine folosiți un helper de runtime combinat cu aserțiuni de tip mai relaxate.

Voi cum gestionați permisiunile în proiectele mari de TS? Mergeți pe enums clasice sau lăsați totul pe string-uri și vă bazați pe teste?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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