October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk3 min

TypeScript `using` in Real Codebases: Database Connections, File Handles, and Async Disposal Done Right

TypeScript’s `using` and `await using` handle scope-bound cleanup for resources that implement explicit disposal. See practical file-handle and transaction patterns, plus key runtime and lifetime caveats.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use await using for Node.js file handles

A Node.js file handle can be opened and disposed like this:

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 Programming Language - Software Engineer & Coder T-Shirt
  • 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

await 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.

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.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.