swc-project/swc · error · TypeError

using declarations can only be used with objects, functions,

Error message

using declarations can only be used with objects, functions, null, or undefined.

What it means

`_using` is the helper SWC emits for `using` declarations under explicit-resource-management downleveling (min ES 7.22 per its header). It rejects primitives with `Object(value) !== value` and throws `TypeError: using declarations can only be used with objects, functions, null, or undefined.` — the spec rule that resources must be disposable objects.

Source

Thrown at crates/swc_ecma_transforms_base/src/helpers/generated/_using.rs:15

// This file is generated by `cargo codegen helpers`. DO NOT MODIFY.

use super::{HelperDef, HelperName};

pub const DEF: HelperDef = HelperDef {
    name: HelperName::using,
    local: "_using",
    import_path: "@swc/helpers/_/_using",
    #[cfg(feature = "inline-helpers")]
    source: r#"/* @minVersion 7.22.0 */

function _using(stack, value, isAwait) {
    if (value === null || value === void 0) return value;
    if (Object(value) !== value) {
        throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
    }
    // core-js-pure uses Symbol.for for polyfilling well-known symbols
    if (isAwait) {
        var dispose = value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")];
    }
    if (dispose === null || dispose === void 0) {
        dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")];
    }
    if (typeof dispose !== "function") {
        throw new TypeError(`Property [Symbol.dispose] is not a function.`);
    }
    stack.push({ v: value, d: dispose, a: isAwait });
    return value;
}
"#,
    #[cfg(feature = "inline-helpers")]
    deps: super::HelperBitmap::from_bits(0x00000010000000000000000000000000),
};

View on GitHub (pinned to 5176682b65)

Solutions

  1. Restrict `using` to objects/functions implementing `[Symbol.dispose]` (or null/undefined for no-op scoping).
  2. Wrap primitive handles: `using h = { [Symbol.dispose]: () => closeHandle(id), id };`.
  3. Keep primitives in `try/finally` blocks and use `using` only for object resources.
  4. Narrow the acquire function's return type so primitives are rejected at compile time.

Example fix

// before
using handleId = acquireHandle(); // acquireHandle(): number
// TypeError: using declarations can only be used with objects, functions, null, or undefined.

// after
const id = acquireHandle();
using handle = { [Symbol.dispose]: () => releaseHandle(id) };
Defensive patterns

Strategy: type-guard

Validate before calling

// Same rule as _using: Object(value) === value, or null/undefined.
const isUsingCompatible = (v) => v === null || v === undefined || Object(v) === v;
const res = acquire();
if (!isUsingCompatible(res)) {
  throw new TypeError(`using got primitive ${typeof res} — wrap it in a disposable object`);
}

Type guard

const isUsingCompatible = (v: unknown): v is object | null | undefined =>
  v == null || (typeof v === 'object' || typeof v === 'function');

Prevention

When it happens

Trigger: `using x = 42;` / `using s = 'str';` / any primitive resource in code whose `using` declarations were compiled to `_using` (Babel-compatible output from SWC's compat pass).

Common situations: Adopting the `using` proposal with wrapper libraries (like TypeScript's TempFile examples) but letting a primitive slip in from a union-typed acquire function; refactoring try/finally cleanup to `using` where the resource is a number handle.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/d52a25ec219293a2. Report an issue: GitHub.