Check whether a value is NaN and a numeric type (Number.isNaN)

Number.isNaN(value) tells you one very specific thing: is the argument the numeric value NaN? It answers “yes” only when the input is of the JavaScript Number type and that number is the special IEEE-754 Not-a-Number payload. It never coerces non-numbers. If you pass a string, boolean, null, or anything else, it returns false. This makes it the precise, modern way to detect the actual NaN number.

Number.isNaN(NaN);            // true
Number.isNaN(0 / 0);          // true
Number.isNaN("NaN");          // false  ← not a number type
Number.isNaN(undefined);      // false
Number.isNaN("123");          // false

Why not just use the global isNaN?

The legacy isNaN(value) first coerces its argument with Number(value), then checks whether the result is NaN. That coercion causes false positives and surprises. For example, isNaN("foo") is true because "foo" isn’t convertible to a number, while isNaN("") is false because the empty string coerces to 0. Number.isNaN avoids all of that by refusing to coerce. Use it anytime you care about the exact numeric state rather than “would this become NaN if I converted it.”

isNaN("foo");            // true   (coerces to NaN)
Number.isNaN("foo");     // false  (no coercion)

isNaN("");               // false  ("" → 0)
Number.isNaN("");        // false  (not a number)

isNaN(true);             // false  (true → 1)
Number.isNaN(true);      // false

The exact semantics you can rely on

Number.isNaN is a simple predicate: it returns true if and only if its single argument is of type Number and is the IEEE-754 NaN value. No conversions happen. That strictness is what differentiates it from isNaN. The specification phrases this in terms of “the number value NaN” and explicitly notes that non-Number inputs return false.

Number.isNaN(NaN);                 // true
Number.isNaN(new Number(NaN));     // false (the value is an object, not a Number primitive)
Number.isNaN(+("not-a-number"));   // true  (you coerced it yourself; result is a Number NaN)

Equality won’t help; use Number.isNaN or Object.is

NaN is the only JavaScript number that isn’t equal to itself. That’s why x === x fails for NaN. Historically, developers used x !== x as a NaN test. Today, Number.isNaN(x) is the intent-revealing version. If you’re comparing two values and want NaN to match NaN, Object.is(a, b) does exactly that and also distinguishes +0 from -0.

NaN === NaN;                  // false
Object.is(NaN, NaN);          // true
Number.isNaN(NaN);            // true

Object.is(+0, -0);            // false
+0 === -0;                    // true

Practical patterns for real code

When you accept numeric input, parse first, then check with Number.isNaN to handle failed conversions cleanly. This keeps parsing logic clear and avoids ever calling isNaN on raw, unparsed data.

function readNumber(input) {
  const n = Number(input);        // or parseFloat/parseInt as appropriate
  return Number.isNaN(n) ? null : n;
}

readNumber(" 12.5 ");   // 12.5
readNumber("twelve");   // null

When computing, treat NaN as contagious. If any intermediate step becomes NaN, the result often propagates to NaN. A final Number.isNaN(result) check is a straightforward guardrail for math-heavy code.

function divide(a, b) {
  const q = a / b;
  if (Number.isNaN(q)) throw new Error("Invalid division");
  return q;
}

divide(0, 0);  // throws (0/0 is NaN)

Common edge cases worth internalizing

Objects don’t magically unwrap. A Number object wrapper is not a Number primitive, so it returns false. Strings that look like "NaN" are still strings. If you need to treat those as numbers, convert them first and then test the numeric result with Number.isNaN.

Number.isNaN(new Number(NaN));   // false
Number.isNaN("NaN");             // false
Number.isNaN(Number("NaN"));     // true

Be mindful of Infinity and -Infinity. They’re numbers, but they’re not NaN, so both predicates return false. If you need to reject non-finite values in general, combine checks.

Number.isNaN(Infinity);   // false
Number.isNaN(-Infinity);  // false

function isFiniteNumber(x) {
  return typeof x === "number" && Number.isFinite(x);
}

A quick mental model to choose the right check

Reach for Number.isNaN(x) when you’ve already produced a number (by calculation or conversion) and you need to know if it’s specifically the NaN value. Reach for Object.is(x, NaN) when comparing two arbitrary values where NaN should equal NaN. Avoid the global isNaN(x) unless you explicitly want the “after coercion” question it answers. These distinctions are formalized in the language reference and summarized in current platform docs.

const x = Number("oops");     // NaN
Number.isNaN(x);              // true  ← best signal after conversion

Object.is(x, NaN);            // true  ← equality that treats NaN as equal

isNaN("oops");                // true  ← because it coerces first

References

SourceWhat it covers
MDN: Number.isNaN()Exact semantics, non-coercing behavior, examples, and guidance to prefer Number.isNaN over the global isNaN.
MDN: isNaN()Legacy global predicate, its coercion step, and why it can be misleading for validation.
MDN: Object.is()Same-value equality semantics, special handling for NaN and signed zeros.
ECMAScript® Language Specification (latest snapshot)Normative definitions that underpin NaN semantics, same-value equality, and number behavior.