microsoft/TypeScript · error · TypeError
Cannot use 'in' operator on non-object
Error message
Cannot use 'in' operator on non-object
What it means
Runtime TypeError from the `__classPrivateFieldIn` helper, which lowers `#field in expr`. Before the brand check it guards the receiver: if `receiver === null` or `typeof receiver` is neither `"object"` nor `"function"`, it throws. The native `in` operator has the same requirement, but this message comes from the downlevel helper.
Source
Thrown at src/compiler/factory/emitHelpers.ts:1375
/**
* Parameters:
* @param state — One of the following:
* - A WeakMap when the member is a private instance field.
* - A WeakSet when the member is a private instance method or accessor.
* - A function value that should be the undecorated class constructor when the member is a private static field, method, or accessor.
* @param receiver — The object being checked if it has the private member.
*
* Usage:
* This helper is used to transform `#field in expression` to
* `__classPrivateFieldIn(<weakMap/weakSet/constructor>, expression)`
*/
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) {
View on GitHub (pinned to b465fdbfe1)
Solutions
- Narrow the operand before the `in` check: `typeof o === "object" && o !== null && #x in o`.
- Type the parameter as `object` (or the declaring class) so primitives are rejected statically.
- Guard nullish values upstream so the `in` expression only ever sees objects.
- Raise `target` to ES2022+ to get the native spec error.
Example fix
// before
function branded(o: any) {
return #x in o; // throws if o is null/undefined/primitive
}
// after
function branded(o: unknown) {
return typeof o === "object" && o !== null && #x in o;
} Defensive patterns
Strategy: validation
Validate before calling
function isBranded(o: unknown): boolean {
return typeof o === "object" && o !== null && #x in o;
} Type guard
function isObjectLike(o: unknown): o is object { return typeof o === "object" && o !== null; } Prevention
- Always narrow `unknown`/`any` to `object` before any `#x in o` brand check.
- Validate at the trust boundary so primitives never reach brand-check code.
When it happens
Trigger: Evaluating `#x in value` where `value` is `null`, `undefined`, or a primitive (number/string/boolean/symbol/bigint), in code compiled with the `__classPrivateFieldIn` helper. Also reached by calling `__classPrivateFieldIn(state, primitive)` directly.
Common situations: User input or parsed values fed into a `#brand in obj` check without coercion; generic utility code that accepts `unknown`/`any` and runs a private-brand test; nullish short-circuits that were forgotten.
Related errors
- Private accessor was defined without a getter
- Cannot read private member from an object whose class did no
- Private method is not writable
- Private accessor was defined without a setter
- Cannot write private member to an object whose class did not
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/5ab5e7e03589fa60.
Report an issue: GitHub.