Intermediate0 questionsFull Guide

JavaScript Type Coercion Interview Questions

Type coercion is behind many JavaScript gotchas. Learn == vs ===, implicit conversion rules, and how to answer tricky output questions.

The Mental Model

JavaScript is like an overly helpful translator who never admits they don't understand something. When you give it two different types to compare or combine, instead of stopping and saying "these don't match," it quietly converts one value into a type it can work with — and then proceeds. This conversion is type coercion. The problem is that the "translation" follows rules that are consistent but deeply unintuitive. JavaScript isn't random — it's following a spec — but the spec's rules produce results that look like bugs until you've studied them. There are two kinds: implicit coercion (JavaScript does it automatically, without you asking) and explicit coercion (you do it intentionally with Number(), String(), Boolean()). The key to mastering coercion is learning the three conversion algorithms JavaScript uses internally: ToNumber, ToString, and ToBoolean. Once you know the tables, the "weird" results stop being surprising.

The Explanation

The three conversion algorithms

ToBoolean — what's falsy?

There are exactly 8 falsy values in JavaScript. Everything else is truthy.

Falsy valueNotes
falsethe boolean false
0positive zero
-0negative zero
0nBigInt zero
""empty string (any empty string)
null
undefined
NaN

Truthy surprises — values you might expect to be falsy that aren't:

Boolean("0")        // true  — non-empty string, even if it's "0"
Boolean("false")    // true  — non-empty string
Boolean([])         // true  — empty array is truthy
Boolean({})         // true  — empty object is truthy
Boolean(function(){}) // true
Boolean(-1)         // true  — any non-zero number

ToNumber — converting to a number

Number(true)        // 1
Number(false)       // 0
Number(null)        // 0
Number(undefined)   // NaN
Number("")          // 0
Number(" ")         // 0  (whitespace strings → 0)
Number("42")        // 42
Number("3.14")      // 3.14
Number("42abc")     // NaN  (can't fully parse)
Number([])          // 0   ([] → "" → 0)
Number([3])         // 3   ([3] → "3" → 3)
Number([1,2])       // NaN ([1,2] → "1,2" → NaN)
Number({})          // NaN ({} → "[object Object]" → NaN)

ToString — converting to a string

String(true)        // "true"
String(false)       // "false"
String(null)        // "null"
String(undefined)   // "undefined"
String(0)           // "0"
String(-0)          // "0"  ← watch out
String([1,2,3])     // "1,2,3"
String([])          // ""
String({})          // "[object Object]"

The + operator — string concatenation beats addition

The + operator is the most dangerous source of implicit coercion. Its rule: if either operand is a string (or can be converted to one), it concatenates. Otherwise it adds.

"5" + 3          // "53"  — 3 coerced to string
5 + "3"          // "53"
"5" + true       // "5true"
"5" + null       // "5null"
"5" + undefined  // "5undefined"
5 + null         // 5    — null coerced to 0
5 + undefined    // NaN  — undefined coerced to NaN
5 + true         // 6    — true coerced to 1
[] + []          // ""   — both become "", concatenated
[] + {}          // "[object Object]"
{} + []          // 0    — {} parsed as empty block, +[] = 0

Arithmetic operators — always convert to numbers

-, *, /, %, ** always trigger ToNumber on both operands.

"5" - 3          // 2    — "5" → 5
"5" * "2"        // 10   — both to numbers
true + true      // 2    — both → 1
false * 5        // 0
null * 5         // 0    — null → 0
undefined * 5    // NaN  — undefined → NaN
"abc" - 1        // NaN  — "abc" → NaN

Comparison operators and coercion

The == (loose equality) algorithm follows a specific set of coercion rules. Understanding them is the key to the "weird" outputs you see in interviews.

// Type matching — no coercion
1 == 1          // true
"a" == "a"      // true

// null == undefined — special case, always true
null == undefined   // true
null == 0           // false  ← critical interview trap
null == false       // false
undefined == false  // false

// Number vs String — string converts to number
"42" == 42      // true   ("42" → 42)
"0" == 0        // true   ("0" → 0)
"" == 0         // true   ("" → 0)

// Boolean vs anything — boolean converts to number FIRST
true == 1       // true   (true → 1)
false == 0      // true   (false → 0)
true == "1"     // true   (true → 1, then "1" == 1, "1" → 1)
false == ""     // true   (false → 0, "" → 0)
false == "0"    // true   (false → 0, "0" → 0)

// Object vs primitive — calls valueOf() or toString()
[0] == false    // true   ([0] → "0" → 0, false → 0)
[] == false     // true   ([] → "" → 0, false → 0)
[] == 0         // true   ([] → "" → 0)
"" == false     // true   (false → 0, "" → 0)

The Abstract Equality Comparison algorithm (simplified)

  1. Same type? Use strict equality (===).
  2. null and undefined? Always true to each other, always false to everything else.
  3. Number and string? Convert string to number, compare.
  4. Boolean and anything? Convert boolean to number first, then re-compare.
  5. Object and primitive? Call ToPrimitive on the object (tries valueOf() then toString()), compare result.

Explicit coercion — the safe way

// To number
Number("42")          // 42 — clearest
parseInt("42px", 10)  // 42 — parses integer, stops at non-numeric
parseFloat("3.14em")  // 3.14
+"42"                 // 42 — unary + (common, but less readable)
"42" * 1              // 42 — works but confusing

// To string
String(42)            // "42" — clearest
(42).toString()       // "42"
`${42}`               // "42" — template literal

// To boolean
Boolean(value)        // clearest
!!value               // common shorthand — double negation

NaN — the most bizarre value

typeof NaN          // "number" — NaN is a number type
NaN === NaN         // false    — NaN is not equal to itself
NaN == NaN          // false    — same

// Correct way to check for NaN:
Number.isNaN(NaN)   // true
Number.isNaN("NaN") // false — doesn't coerce, unlike global isNaN()
isNaN("abc")        // true  — global isNaN coerces first, unreliable

Common Misconceptions

⚠️

Many devs think empty array [] is falsy — but actually [] is truthy. Only 8 specific values are falsy in JavaScript, and empty array is not one of them. Boolean([]) === true. This trips up nearly every developer at least once.

⚠️

Many devs think null == false is true — but actually null only loosely equals undefined and nothing else. null == false is false. null == 0 is false. This is a special-cased exception in the == algorithm specifically to make null checks safe with ==.

⚠️

Many devs think + always does addition — but actually + is string concatenation when either operand is a string. The moment one side is a string, the other is converted to string and they're concatenated. "5" + 3 is "53", not 8. Subtraction, multiplication, and division always convert to numbers — only + has this dual behaviour.

⚠️

Many devs think the fix for coercion bugs is to always use === — but actually === only prevents type coercion in comparisons. Arithmetic coercion (like "5" - 3) still happens with strict equality elsewhere in the code. Understanding coercion is the real fix; === is just one defensive tool.

⚠️

Many devs think NaN means "not a number in type" — but actually typeof NaN === "number". NaN is a numeric value that represents an invalid computation result. It's still the Number type. The check NaN === NaN is false because IEEE 754 floating point defines it that way — use Number.isNaN() instead.

⚠️

Many devs think explicit coercion like Number() and String() is the same as implicit coercion — but actually they follow the same conversion algorithms (ToNumber, ToString). The difference is intent: explicit coercion is deliberate and readable, implicit happens as a side effect and is often surprising.

Where You'll See This in Real Code

JSON.stringify coerces values silently — undefined, functions, and symbols are dropped from objects entirely, not converted to strings. Arrays with these values get null substituted. Production bugs have been caused by assuming JSON serialization preserves all values.

Form input values in the browser are always strings — document.getElementById('age').value returns "25", not 25. Arithmetic on form values without explicit conversion produces string concatenation. This bug ships to production constantly: "25" + 1 = "251" instead of 26.

localStorage and sessionStorage only store strings — storing a number or boolean and reading it back gives you a string. Developers who don't know this write bugs where stored settings like "false" are truthy when read back.

React's conditional rendering uses truthiness checks — rendering {count && <Component />} will render the number 0 when count is 0, not nothing, because 0 is falsy but React renders falsy numbers as text. The correct pattern is {count > 0 && <Component />} or {Boolean(count) && <Component />}.

TypeScript exists largely because of JavaScript's coercion model — the entire point of a type system is to catch the class of bugs where two incompatible types meet unexpectedly and coercion silently produces a wrong result. Understanding coercion helps you understand why TypeScript's type errors matter.

The == operator is not always wrong — null == undefined is a useful pattern for checking "this value was either not provided or explicitly cleared" with a single check instead of value === null || value === undefined. Many style guides allow this specific use of ==.

Interview Cheat Sheet

  • == uses abstract equality with type coercion; === uses strict equality without conversion
  • Falsy values: false, 0, "", null, undefined, NaN, 0n — everything else is truthy
  • When comparing with ==: null == undefined is true; null == 0 is false
  • String + number: number converts to string ("1" + 2 = "12")
  • String - number: string converts to number ("3" - 1 = 2)
💡

How to Answer in an Interview

  • 1.Output prediction questions love coercion — practice [] + {}, {} + [], typeof null
  • 2.Always use === in production; explain WHY: predictable, no surprise coercion
  • 3.Mention Symbol.toPrimitive for custom coercion at senior level
📖 Deep Dive Articles
null vs undefined in JavaScript: What They Mean, When They Appear, and How to Handle Each7 min read== vs === in JavaScript: Equality, Coercion, and When Each Actually Applies8 min readTop 50 JavaScript Interview Questions (With Deep Answers)18 min readJavaScript Output Questions: 30 Tricky Examples That Test Real Understanding14 min read

Practice Questions

No questions tagged to this topic yet.

Tag questions in Admin → Questions by setting the "Topic Page" field to javascript-type-coercion-interview-questions.

Related Topics

JavaScript Closure Interview Questions
Intermediate·8–12 Qs
JavaScript == vs === Interview Questions
Beginner·3–5 Qs
🎯

Can you answer these under pressure?

Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.

Practice Free →Try Output Quiz