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
- Restrict `using` to objects/functions implementing `[Symbol.dispose]` (or null/undefined for no-op scoping).
- Wrap primitive handles: `using h = { [Symbol.dispose]: () => closeHandle(id), id };`.
- Keep primitives in `try/finally` blocks and use `using` only for object resources.
- 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
- Keep acquire functions' return types narrow (`Disposable | null`) so primitives are a compile-time error.
- Do not use `|| 0`-style primitive fallbacks in `using` initializers.
- Wrap primitive handles (fds, ids) in a `{ [Symbol.dispose] }` adapter at the boundary.
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
- Object expected.
- Object not disposable.
- Property [Symbol.dispose] is not a function.
- using declarations can only be used with objects, functions,
- Symbol.dispose is not defined.
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/d52a25ec219293a2.
Report an issue: GitHub.