Il 24 agosto 2023 Microsoft ha rilasciato TypeScript 5.2 con una novità che sembra piccola ma che, una volta provata, è difficile lasciare: la keyword using. Anticipa la proposta Explicit Resource Management di ECMAScript (oggi allo stage 3) ed elimina una fonte cronica di bug nei progetti Node.
Il problema: chi chiude la risorsa?
Tutti abbiamo scritto codice come questo:
const file = await fs.open("data.txt");
try {
// usa il file
} finally {
await file.close();
}
Funziona, ma è verboso. Quando le risorse diventano due, tre o quattro, gli annidamenti di try/finally diventano un labirinto. E se qualcuno dimentica un finally, la risorsa rimane aperta finché non interviene il garbage collector — o non interviene affatto.
La soluzione: using
Con TypeScript 5.2 si scrive così:
using file = await fs.open("data.txt");
// uso il file
// alla fine dello scope viene chiamato file[Symbol.dispose]()
Il runtime invoca Symbol.dispose in modo automatico all'uscita dallo scope, che sia per ritorno normale, eccezione o break. Per le risorse asincrone esiste await using, che chiama Symbol.asyncDispose.
Quando ci serve davvero
Negli script di onboarding clienti che scriviamo regolarmente, capita di gestire connessioni a database, lock su file di configurazione e session su servizi esterni tutti nello stesso flusso. Con using il codice diventa lineare e impossibile da dimenticare. Anche per i Server Actions di Next.js abbiamo iniziato a creare wrapper che dispongono automaticamente di transazioni Prisma.
function transaction() {
const tx = prisma.$begin();
return {
tx,
[Symbol.asyncDispose]: () => tx.commit(),
};
}
await using t = transaction();
await t.tx.user.update(...);
// commit automatico
Cosa serve per usarlo
Il target di compilazione deve supportare Symbol.dispose. TypeScript fa polyfill per i target più vecchi tramite l'helper __addDisposableResource. Su Node.js servono almeno la 20.x con flag o, ancora meglio, la 22 LTS che è arrivata nel 2024. Per i runtime più recenti (Bun, Deno) il supporto è già nativo.
Vale la migrazione?
Non è una feature che giustifica un refactoring di massa. È però una di quelle che, una volta entrata nelle mani del team, riduce silenziosamente i bug. La nostra regola: using obbligatorio per qualunque risorsa con open/close, connect/disconnect, lock/unlock. Per il resto, lasciamo stare.