using & await using (TS 5.2 Explicit Resource Management)
debt(d7/e3/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list TypeScript as the only tool and mark automated as 'no', with the code_pattern being finally.*\.close\( or finally.*\.disconnect\( — meaning misuse (forgetting to use `using`, or forgetting `await using` for async cleanup) isn't caught by default linting but requires code review to spot try/finally patterns that should be converted, or runtime leaks to surface the problem.
Closest to 'simple parameterised fix' (e3). The quick_fix describes replacing try/finally blocks with using/await using and implementing Symbol.dispose on resource classes — a recurring pattern replacement within a component, but not purely a one-line swap since custom resource classes need [Symbol.dispose]() implemented and async cases need [Symbol.asyncDispose](), touching a small set of related files.
Closest to 'localised tax' (b3). The applies_to scope covers web and cli contexts broadly, but the burden is per-resource class: developers must remember to implement Symbol.dispose or Symbol.asyncDispose on custom resources. This is a localised convention tax — it doesn't reshape the whole codebase, but every resource abstraction must carry this obligation.
Closest to 'notable trap' (t5). The misconception field explicitly states devs wrongly believe `using` only works with built-in types, missing that any object implementing [Symbol.dispose]() qualifies. Additionally, the common_mistakes cite forgetting `await using` for async cleanup and misusing it outside block scope — multiple documented gotchas that competent developers encounter and must learn.
TL;DR
Explanation
using x = getResource() calls x[Symbol.dispose]() when the variable goes out of scope (block end, return, throw). await using x = getResource() calls x[Symbol.asyncDispose]() and awaits it. This enables deterministic cleanup without try/finally boilerplate. Implementing: add [Symbol.dispose]() to your class. Use cases: database connections, file handles, event listeners, locks, timers. The DisposableStack and AsyncDisposableStack helpers manage multiple disposables. Part of the TC39 Explicit Resource Management proposal.
Common Misconception
Why It Matters
Common Mistakes
- Not implementing Symbol.dispose on custom resources.
- Forgetting await using for async cleanup (DB connections, streams).
- Using in non-block scope — using only works in block-scoped contexts.
Code Examples
// Verbose try/finally:
const conn = await db.connect();
try {
await conn.query('SELECT 1');
} finally {
await conn.close(); // Easy to forget
}
// TypeScript 5.2+:
class DbConnection implements AsyncDisposable {
async [Symbol.asyncDispose]() {
await this.close();
}
}
async function query() {
await using conn = await db.connect();
await conn.query('SELECT 1');
} // conn.close() called automatically