Gyaan

Data Types & Type Coercion

beginner types coercion equality truthy falsy

JavaScript has two categories of data types — primitive and reference. Understanding this distinction is key because they behave very differently in terms of how they are stored and compared.

Primitive types

There are 7 primitive types. These are immutable — when we “change” a string or number, we are actually creating a new value.

string
"hello"
number
42, 3.14, NaN
boolean
true, false
null
intentional empty
undefined
not assigned
symbol
unique identifier
bigint
9007199254740991n

Primitives are stored directly in the stack — the variable holds the actual value.

Reference types

Reference types include objects, arrays, and functions. These are stored in the heap, and the variable holds a reference (pointer) to the memory location.

const a = { name: "Manish" };
const b = a; // b points to the same object in memory
b.name = "Pika";
console.log(a.name); // "Pika" — both reference the same object

typeof quirks

The typeof operator has a couple of famous gotchas that come up in interviews all the time:

typeof "hello"     // "string"
typeof 42          // "number"
typeof true        // "boolean"
typeof undefined   // "undefined"
typeof Symbol()    // "symbol"
typeof 10n         // "bigint"
typeof {}          // "object"
typeof []          // "object"  — arrays are objects!
typeof null        // "object"  — this is a known JS bug since day 1
typeof NaN         // "number"  — NaN is technically "Not a Number" but its type is number
typeof function(){} // "function"

The typeof null === "object" is a bug from the very first version of JavaScript that was never fixed for backward compatibility reasons. To check for null, just use value === null.

Type coercion: == vs ===

This is one of the most asked interview questions. In simple language:

  • === (strict equality) compares value and type — no conversion happens
  • == (loose equality) converts the values to the same type first, then compares
0 == ""        // true  — both coerced to 0
0 === ""       // false — number vs string
false == 0     // true  — false becomes 0
false === 0    // false — boolean vs number
null == undefined  // true  — special rule, they are loosely equal
null === undefined // false — different types
"1" == 1       // true  — string "1" converted to number 1
"1" === 1      // false — string vs number

The golden rule is: always use === unless you have a very specific reason to use ==. The only common exception is checking value == null which catches both null and undefined in one check.

Truthy and falsy values

In JavaScript, every value is either “truthy” or “falsy” — meaning it evaluates to true or false when used in a boolean context (like an if statement).

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

Falsy (8 values)
false
0
-0
0n (BigInt zero)
"" (empty string)
null
undefined
NaN
Truthy (everything else)
"0" (non-empty string)
"false" (non-empty string)
[] (empty array!)
{} (empty object!)
function(){}
42, -1, Infinity
...any non-falsy value

A common gotcha: empty arrays [] and empty objects {} are truthy. This trips up a lot of people.

if ([])  console.log("truthy"); // prints "truthy" — empty array is truthy!
if ({})  console.log("truthy"); // prints "truthy" — empty object is truthy!
if ("0") console.log("truthy"); // prints "truthy" — non-empty string is truthy!
if (0)   console.log("truthy"); // does NOT print — 0 is falsy

Explicit coercion

We can manually convert types using Number(), String(), and Boolean():

Number("42")      // 42
Number("")        // 0
Number("hello")   // NaN
Number(true)      // 1
Number(null)      // 0
Number(undefined) // NaN

String(42)        // "42"
String(null)      // "null"
String(undefined) // "undefined"

Boolean(0)        // false
Boolean("")       // false
Boolean("hello")  // true
Boolean([])       // true — again, empty array is truthy!

Coercion gotchas

These are the kind of examples interviewers love to throw at you:

"5" + 3      // "53"  — + with a string triggers string concatenation
"5" - 3      // 2     — minus always does math, so "5" becomes 5
true + true  // 2     — true is 1, so 1 + 1
[] + []      // ""    — both become empty strings, "" + ""
[] + {}      // "[object Object]" — array becomes "", object becomes "[object Object]"
{} + []      // 0     — {} is parsed as empty block, so it's just +[] which is 0

In simple language, the + operator is the main troublemaker. If either side is a string, it does string concatenation. All other math operators (-, *, /) will try to convert both sides to numbers.