The Safest Way to Test for NaN in JavaScript

Abstract image used to represent The Safest Way to Test for NaN in JavaScript
Image by Mick Haupt.

In Brief

Use Number.isNaN(value) when you need to know whether a value is the actual numeric NaN value. Unlike the global isNaN(), it does not coerce strings or other inputs before testing them. Direct equality checks cannot work because NaN is not equal to itself, whilst typeof NaN returns "number" and therefore cannot distinguish it.

A NaN or Not a Number is an unusual thing in JavaScript development and often presents itself as a spanner in the works for new developers when first working with numbers or equations. Typically it comes up when a variable unexpectedly returns a string or a boolean (rather than a number), whilst your code attempts to do calculations with it. We've all encountered NaN before, and it can prove to be a bit of a nightmare when it comes up unexpectedly.

In code safeguarding practices, it is worth being able to test against any essential data source. There are a few ways to test for NaN, but even the common methods to test it have some surprising quirks.


Don't compare against NaN

I will often find a team member I'm mentoring who will already have tried this if they come across this problem. The thought process is sound: we should simply check the variable against NaN, in exactly the same way we can for undefined or null, right?

The == and === equality operators both return false when comparing NaN with itself:

const nonNumber = 1 * 'this is a string';

// both of these are 'false'
nonNumber == NaN;
nonNumber === NaN;

That is the equality rule for NaN; it is not evidence that each failed calculation produces a different identity. Other comparisons have different rules: Object.is(NaN, NaN), for example, returns true.


Don't use typeof

As if not being able to do a hard check wasn't baffling enough, the next option should be to check typeof which also will not work. In JavaScript (and other computing languages), NaN is still recognised as a number:

const nonNumber = 1 * 'this is a string';

// this will return 'number'
typeof nonNumber;

Despite its name, NaN is a value of JavaScript's number type. That is why typeof cannot distinguish it from an ordinary number.


isNaN()

The global isNaN() function first converts its argument to a number, then tests whether that result is NaN. That conversion can be surprising: isNaN("12"), isNaN(null) and isNaN(false) all return false, whilst a string that cannot convert to a number returns true:

const nonNumber = 1 * 'this is a string';

// this will return 'true'
isNaN(nonNumber);


const aString = 'this is not a number either';

// this will also return 'true'
isNaN(aString);

The Solution: Number.isNaN()

Number.isNaN() tests whether its argument is the actual numeric NaN value, without first converting it. A string therefore returns false, even if converting that string to a number would produce NaN:

const nonNumber = 1 * 'this is a string';

// this will return 'true'
Number.isNaN(nonNumber);

const yourString = 'this is not a number either';

// this will return 'false'
Number.isNaN(yourString);

Use Number.isNaN() when that is the condition you need to detect. It does not validate every possible input for a calculation: strings, infinities and outofrange numbers need whatever checks your application requires. The method was added in ES2015, so older browsers may need a fallback.

A small fallback is value !== value: NaN is the only JavaScript value for which that expression is true. This relies specifically on strict equality's treatment of NaN.


Want to find out more?

If you need senior handson support with a complex React or Next.js platform, migration, performance issue, or technical SEO problem, send me the context and I'll tell you where I can help.