Type Conversion and Coercion
Understand how to explicitly convert values between types, how JavaScript implicitly coerces types on its own, and how that affects equality comparisons.
Because JavaScript is dynamically and loosely typed, values are frequently converted between types — sometimes explicitly by the developer, and sometimes automatically by JavaScript itself, which is a frequent source of bugs if not well understood.
Explicit conversion: String(), Number(), Boolean()
Explicit (or "type casting") conversion means the developer deliberately converts a value from one type to another using a built-in function. String(value) converts any value to its string representation, Number(value) converts a value to a number (or to NaN if it cannot be meaningfully converted), and Boolean(value) converts a value to true or false based on JavaScript's "truthy/falsy" rules.
These conversions are explicit and intentional, which makes code easier to read and debug compared to relying on JavaScript to convert types automatically behind the scenes.
parseInt() and parseFloat()
parseInt(string, radix) reads through a string from the start and extracts as many valid digits as it can to form an integer, ignoring any trailing non-numeric characters — parseInt("42px") returns 42. The second argument (radix, typically 10) sets the numeral base and should generally always be specified explicitly to avoid ambiguity.
parseFloat(string) works the same way but also captures a decimal point, returning a floating-point number — parseFloat("3.14 meters") returns 3.14. Both functions return NaN if the string does not begin with anything that looks like a valid number, which differs from Number(), which returns NaN for a string containing any invalid characters anywhere, not just at the end.
Implicit coercion
Implicit coercion happens automatically, without an explicit conversion function, whenever an operator or context expects a different type than what it was given. The most notorious example is the + operator: if either side of + is a string, JavaScript converts the other side to a string and concatenates them, rather than performing addition — 1 + "2" produces "12", not 3.
Other operators behave differently: -, *, /, and % always coerce both sides toward numbers, so "5" - 2 produces 3 (a number). This inconsistency (+ favors strings when either side is a string, but the other arithmetic operators favor numbers) is one of the most important quirks to memorize in JavaScript.
Truthy and falsy values
When a value is used somewhere a boolean is expected (like an if condition), JavaScript implicitly coerces it to true or false. There are exactly eight falsy values in JavaScript: false, 0, -0, 0n (BigInt zero), "" (empty string), null, undefined, and NaN. Every other value — including "0", "false", empty objects {}, and empty arrays [] — is truthy.
Strict vs loose equality
The loose equality operator == performs type coercion before comparing: if the two operands are different types, JavaScript converts one or both to a common type first, then compares — "5" == 5 is true because the string is coerced to a number first.
The strict equality operator === compares both value and type with no coercion at all: "5" === 5 is false, because a string is never equal to a number under strict equality, regardless of what it looks like. The universally recommended practice in modern JavaScript is to always use === (and !==) instead of == (and !=), so comparisons behave predictably and coercion bugs are avoided.
Explicit conversion functions
Always pass a radix (usually 10) to parseInt to avoid ambiguous interpretation of strings like "08". Number("") is 0, but Number(" ") (whitespace only) is also 0 — while Number(undefined) is NaN. String("0") and the number 0 look related but are very different: "0" is truthy, 0 is falsy.
String(123); // "123"
String(true); // "true"
String(null); // "null"
Number("42"); // 42
Number("42px"); // NaN
Number(""); // 0
Number(true); // 1
Boolean(0); // false
Boolean(""); // false
Boolean("0"); // true (a non-empty string is always truthy)
parseInt("42px", 10); // 42
parseFloat("3.14m"); // 3.14Code Examples
This shows a very common real-world pattern: converting a string (perhaps from a form input, which is always text) into a number before doing math with it. Expected result: 59.97 number let price = Number(priceText); explicitly converts the string "19.99" into the number 19.99.
This walks through the classic + vs -/* behavior split, and the difference between == and === on the same pair of values. Expected result: 12 3 51 true false
"5" + 2 - 1 evaluates left to right: "5" + 2 becomes "52" (string), then "52" - 1 coerces back to a number, giving 51.
Common mistake: Assuming + always adds numbers is a very common bug source — if either operand is a string, + always concatenates instead.
let priceText = "19.99";
let price = Number(priceText);
let quantity = 3;
console.log(price * quantity);
console.log(typeof price);console.log(1 + "2"); // string concatenation
console.log("5" - 2); // numeric subtraction
console.log("5" + 2 - 1); // concatenate then subtract
console.log("10" == 10); // loose equality: coerces, then compares
console.log("10" === 10); // strict equality: no coercion, types differ== vs === at a glance
== converts operands to a common type before comparing; === never converts and requires both value and type to match.
"10" == 10
│
▼
coerce "10" to number 10
│
▼
10 == 10 → true
"10" === 10
│
▼
no coercion — compare type AND value directly
│
▼
string !== number → falseImportant Rules
Prefer explicit conversion (String(), Number(), Boolean()) over relying on implicit coercion, for clarity.
The + operator concatenates if either side is a string; -, *, /, and % always coerce toward numbers.
There are exactly eight falsy values: false, 0, -0, 0n, "", null, undefined, and NaN — everything else is truthy.
Always prefer === and !== over == and != to avoid unpredictable coercion in comparisons.
Always pass a radix to parseInt(string, radix) to avoid ambiguous number-base interpretation.
Where this shows up
Form inputs, URL query parameters, and data from JSON APIs frequently arrive as strings even when they represent numbers, so explicit conversion with Number() or parseInt()/parseFloat() before doing math is an everyday necessity in real applications.
if (userInput == null) { /* meant to check specifically for null */ } if (userInput === null) { /* only true for exactly null */ }
Loose equality with null is special-cased to also match undefined (null == undefined is true), which can silently hide bugs if you only meant to check for null specifically.
let total = "5" + 3 + 2; // expecting 10 let total = Number("5") + 3 + 2; // 10, or restructure so numbers come first
The + operator evaluates left to right, and since the first operand is a string, everything concatenates as text ("532") instead of adding numerically.
[Predict the Output] What does console.log("3" * "4") log, and what type is the result? A. "34" (string) B. 12 (number) C. NaN D. "12" (string)
B. 12 (number) — Unlike +, the * operator always coerces both operands toward numbers regardless of their original type, so "3" * "4" evaluates as 3 * 4, giving the number 12.
[True / False] 0 == "0" and 0 === "0" both evaluate to true. A. True B. False
B. False — False. 0 == "0" is true because loose equality coerces the string to a number first, but 0 === "0" is false because strict equality never coerces, and a number is never strictly equal to a string.
A form field gives you the string "25" for a user's age. Write code that converts it to a number, adds 5 to it, and logs the result along with its type.
let ageText = "25"; let age = Number(ageText); let futureAge = age + 5; console.log(futureAge, typeof futureAge); // 30 number
Use Number() or parseInt() to convert before doing arithmetic.