microsoft/TypeScript · error · TypeError

Object expected.

Error message

Object expected.

What it means

Runtime TypeError from the `__addDisposableResource` helper, emitted for the Explicit Resource Management feature (`using`/`await using`) when targeting runtimes that lack native support. The helper throws when `value` is neither `null`/`undefined` nor of type `"object"`/`"function"` — i.e. a primitive was bound with `using`.

Source

Thrown at src/compiler/factory/emitHelpers.ts:1387

const classPrivateFieldInHelper: UnscopedEmitHelper = {
    name: "typescript:classPrivateFieldIn",
    importName: "__classPrivateFieldIn",
    scoped: false,
    text: `
            var __classPrivateFieldIn = (this && this.__classPrivateFieldIn) || function(state, receiver) {
                if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object");
                return typeof state === "function" ? receiver === state : state.has(receiver);
            };`,
};

const addDisposableResourceHelper: UnscopedEmitHelper = {
    name: "typescript:addDisposableResource",
    importName: "__addDisposableResource",
    scoped: false,
    text: `
        var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
            if (value !== null && value !== void 0) {
                if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
                var dispose, inner;
                if (async) {
                    if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
                    dispose = value[Symbol.asyncDispose];
                }
                if (dispose === void 0) {
                    if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
                    dispose = value[Symbol.dispose];
                    if (async) inner = dispose;
                }
                if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
                if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
                env.stack.push({ value: value, dispose: dispose, async: async });
            }
            else if (async) {
                env.stack.push({ async: true });
            }
            return value;

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Bind only objects (or null/undefined to skip) with `using`.
  2. Wrap the primitive in a small disposable object (`{ [Symbol.dispose]() {} }`).
  3. Set `target`/`lib` high enough that `using` is emitted natively and the helper is not generated.
  4. Type the `using` variable as a disposable so primitives are rejected at compile time.

Example fix

// before
using handle = 42;             // primitive -> runtime TypeError
// after
using handle = { [Symbol.dispose]() { /* close */ } } as Disposable;
Defensive patterns

Strategy: validation

Validate before calling

// Validate before binding (when types were bypassed):
function asDisposable<T>(v: T): T | null {
  if (v === null || v === undefined) return null;
  if (typeof v !== "object" && typeof v !== "function") throw new TypeError("Object expected");
  return v;
}

Type guard

function isDisposable(v: unknown): v is Disposable { return v !== null && v !== undefined && typeof (v as any)[Symbol.dispose] === "function"; }

Prevention

When it happens

Trigger: Writing `using x = <primitive>` (number, string, boolean, symbol, bigint) where the downlevel helper runs (target without native `using`). Also reached by manual `__addDisposableResource(env, primitive, async)` calls.

Common situations: Binding a configuration value or numeric handle with `using` instead of an object; refactors that assign a primitive to a `using` variable; envs where `using` is transpiled because the target lacks the feature.

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/48bd9c4e9ff87bc6. Report an issue: GitHub.