Why is null + undefined equal to NaN in JavaScript?

In JavaScript, null + undefined returns NaN. To see why, you need to know how JavaScript converts values between types.

Type coercion

Type coercion is converting a value from one type to another. You can do it explicitly in your code, or the JavaScript engine does it implicitly during some operations.

Explicit coercion

Explicit coercion is when you change the type of a value on purpose, with functions like Number(), String(), or Boolean():

let value = '123'
let numberValue = Number(value) // Explicitly coerces string to number
let value = true
let stringValue = String(value) // Explicitly coerces boolean to string

Implicit coercion

Implicit coercion happens when you use an operator on values of different types. The engine converts the values to a common type before it runs the operation. You see this most with +, which does both addition and string concatenation:

let value1 = '123'
let value2 = 456
let result = value1 + value2 // result is "123456" because value2 is implicitly coerced to a string

Here's what happens in that example. value1 is a string and value2 is a number. + can add or concatenate, so the engine has to pick one. The rule is simple: if one of the operands is a string, + concatenates. So the engine converts 456 to '456', joins it with '123', and assigns '123456' to result. You don't write any conversion code. The engine does it for you.

This makes JavaScript forgiving, because operations on mismatched types don't throw errors. It also causes bugs that are hard to find if you don't know the rules. When you know how implicit coercion works, you can predict what your code does and debug it faster.

From null and undefined to NaN

Neither null nor undefined is a string, so + does numeric addition. Two things happen:

  1. Both values convert to numbers. null becomes 0. undefined becomes NaN ("Not a Number").
  2. JavaScript evaluates 0 + NaN, and the result is NaN.

NaN and IEEE 754

JavaScript numbers follow the IEEE 754 floating-point standard. In IEEE 754, any arithmetic operation that involves NaN returns NaN. If one input is undefined, the result is undefined too. That's why 0 + NaN is NaN.

Where TypeScript helps

This is a small example of how loose JavaScript's types are. Sometimes that's useful, and sometimes it causes bugs. It's one reason many developers use TypeScript. Its static types catch many of these mistakes before the code runs.

Coercion rules show up in places you don't expect, so review them now and then. They can save you a long debugging session.