TypeScript’s using and await using declarations dispose resources automatically when their lexical scope ends. Use using for synchronous disposal and await using for asynchronous disposal; acquire resources separately, and make sure each resource implements the corresponding disposal protocol.
What using guarantees
TypeScript 5.2 added support for ECMAScript Explicit Resource Management. A using declaration registers a resource’s [Symbol.dispose]() method to run when the containing scope exits. An await using declaration registers its [Symbol.asyncDispose]() method and waits for that asynchronous cleanup before execution continues beyond the scope.
As an Amazon Associate I earn from qualifying purchases.
Cleanup runs on normal completion and on early exits such as return or throw. Multiple resources are disposed in reverse declaration order: the last resource acquired is disposed first. These declarations are fixed bindings, not a general mechanism for extending or transferring ownership.
Use await using for Node.js file handles
A Node.js file handle can be opened and disposed like this:
#1 Best Overall
import fs from "node:fs/promises";
async function example() {
await using file = await fs.open("example.txt", "r");
console.log(await file.read());
}
The two uses of await have different jobs. await fs.open(...) waits for acquisition and gives the declaration the resolved file handle. await using arranges to await the handle’s asynchronous disposal when the function scope exits. Writing await using file = fs.open(...) is not interchangeable: it gives the declaration a promise rather than the acquired handle.
Model a transaction boundary with async disposal
A transaction wrapper can use [Symbol.asyncDispose]() to decide how to finish based on whether the caller marked the work successful. The TypeScript handbook demonstrates an adapter pattern in which a transaction is created asynchronously, then commits when marked successful and rolls back otherwise.
Rank #2
- TypeScript implements a superset of syntax for strictly typed development, facilitating deep static analysis and enhanced development environment integration. The compiler translates source into standard script formats, ensuring parity across any runtime.
- TypeScript is ideal for front-end developers, full-stack engineers, and software architects who build large-scale web applications. It serves those looking to improve code excellence, reduce bugs through static checking, and maintain complex projects more.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
await using tx = await DatabaseTransaction.create(db);
await performWork(tx);
tx.success = true;
Set the success flag only after the intended work succeeds. If work throws before that point, scope exit invokes disposal and the wrapper can roll back. This is an illustrative wrapper design, not a claim that every database driver implements the explicit-disposal protocol; adapt the pattern to the driver’s actual transaction API.
Choose a lifetime that fits the lexical scope
using works best when a resource’s entire useful lifetime fits within one scope. Nested scopes and multiple declarations unwind in reverse order, which can ensure dependent resources are closed in the right sequence. With asynchronous disposals, that cleanup is awaited sequentially, so registering many independent asynchronous resources can add their cleanup times one after another.
When resources are added conditionally, their lifetime cannot be expressed by one lexical binding, or cleanup callbacks are more appropriate, consider DisposableStack or AsyncDisposableStack. Explicit imperative disposal can also be clearer when a resource must deliberately outlive the scope or its lifetime is controlled elsewhere.
Check TypeScript and runtime support
Before adopting the syntax, verify the project’s TypeScript version, compiler target, library declarations, and runtime support. TypeScript 5.2’s release notes explain that older ECMAScript targets may need a library entry such as esnext.disposable. A runtime may also need disposal-symbol polyfills: transpiling the syntax does not by itself guarantee that Symbol.dispose and Symbol.asyncDispose exist.
Plan for disposal errors and escaped aliases
Disposal can throw. If both the body and disposal fail, TypeScript’s documentation describes a SuppressedError that represents the disposal error and the original error separately. Treat cleanup failures as part of the operation’s error design rather than assuming cleanup cannot affect error handling.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11await using awaits disposal, not acquisition. In an async function with asynchronous disposal, returning a promise without awaiting it can create an unhandled-rejection timing issue; use return await where applicable so the function’s work settles before scope cleanup proceeds.
Best Value
Finally, scope-bound cleanup applies to the binding, not every reference to the underlying object. An alias or closure can outlive the scope and still refer to a resource that has already been disposed. Avoid allowing such references to escape unless callers can reliably tell that the resource is no longer usable.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




