Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A using declaration is a block-scoped variable declaration that guarantees the deterministic execution of a teardown method when the variable’s lexical scope is exited. It implements the ECMAScript Explicit Resource Management proposal, binding the lifecycle of an object to the scope in which it is declared.
// Synchronous declaration
using resource = getResource();

// Asynchronous declaration
await using asyncResource = getAsyncResource();

Protocol Implementation

For an object to be compatible with a using declaration, it must implement the Disposable interface. This requires defining a method keyed by the well-known symbol Symbol.dispose.
class CustomResource implements Disposable {
    [Symbol.dispose](): void {
        // Synchronous teardown logic
    }
}

function getResource() {
    return new CustomResource();
}
For await using declarations, the object must implement the AsyncDisposable interface, utilizing Symbol.asyncDispose. This method must return a Promise. Furthermore, await using has strict context requirements: it can only be used within an asynchronous context, such as inside an async function or at the top level of a module.
class CustomAsyncResource implements AsyncDisposable {
    async [Symbol.asyncDispose](): Promise<void> {
        // Asynchronous teardown logic
    }
}

Execution Mechanics

Scope Exit The disposal method is invoked implicitly at the end of the containing lexical block. This invocation occurs regardless of whether the block exits normally, via a return statement, or due to a thrown exception. Null and Undefined Evaluation Both using and await using declarations gracefully handle null and undefined values. If a resource evaluates to null or undefined, the disposal phase acts as a no-op. This provides a standard pattern for conditionally acquiring resources without requiring complex branching logic during teardown.
// If condition is false, disposal is a no-op
using resource = condition ? getResource() : undefined;
Immutability Variables declared with using or await using are implicitly const. Any attempt to reassign the variable will result in a compiler error. Evaluation Order When multiple using declarations exist within the same scope, their disposal methods are placed on a stack and executed in reverse order of their declaration (Last-In, First-Out).
{
    using a = new ResourceA();
    using b = new ResourceB();
    
    // Scope ends. 
    // b[Symbol.dispose]() is called first.
    // a[Symbol.dispose]() is called second.
}
Exception Handling (SuppressedError) If an exception is thrown during the execution of the block, and the subsequent [Symbol.dispose]() call also throws an exception, the runtime prevents the original error from being lost. It throws a SuppressedError, a built-in Error subclass. The SuppressedError exposes two specific properties:
  • error: The exception thrown during the disposal phase.
  • suppressed: The original exception thrown during the block’s execution.

Compiler Configuration

To utilize using declarations, the TypeScript compiler requires specific target and library configurations in tsconfig.json:
{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["es2022", "esnext.disposable"]
  }
}
If the runtime environment does not natively support Symbol.dispose or Symbol.asyncDispose, a polyfill for these symbols must be provided globally before the declarations are evaluated.
Master TypeScript with Deep Grasping Methodology!Learn More