In With Primitive

ID

javascript.in_with_primitive

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

JavaScript

Tags

reliability, runtime-error, suspicious-comparison

Description

Reports x in y where y is a primitive value — a string, a number, a boolean, null or undefined. The in operator is specified to throw a TypeError unless its right operand is an object, so the expression never produces true or false: it aborts the surrounding function.

if ("length" in "abc") { }      // FLAW — TypeError: Cannot use 'in' operator to search for 'length' in abc
if (0 in 42) { }                // FLAW

const NAME = "widget";
if ("id" in NAME) { }           // FLAW — NAME is a const holding a string

Two operand shapes are recognised and nothing else: a literal written on the spot, and an identifier that resolves to a const binding initialised with such a literal. const is what makes the second case sound — the value can no longer be replaced by an object further down. A let or a var may hold a string on the declaration line and an object at the line being judged, so it is left alone.

Rationale

  • The line is dead on arrival. Unlike a comparison that quietly comes out false, this one throws, so every path that reaches it fails.

  • The mistake is nearly always a confusion with another operation. "b" in "abc" was meant to be "abc".includes("b"); "id" in record was meant to run against an object and the variable holding it turned out to be a primitive.

  • for (const key in "abc") is a different construct and does coerce, so nothing about the loop form warns the author that the operator form does not.

Remediation

Ask the question the operator actually answers, or use the operation that fits the value.

if ("abc".includes("b")) { }       // substring test
if (Object.hasOwn(record, "id")) { }  // own-property test on an object
if ("id" in record) { }            // in, on an object

© 2026 Xygeni. All rights reserved