JavaScript often needs to convert values from one type to another. Sometimes you do this explicitly (type conversion), and sometimes JavaScript does it automatically (type coercion). Understanding the difference—and knowing how to control it—is crucial for writing bug-free code. Let's master type conversion!
Conversion vs Coercion
There are two ways types change in JavaScript:
Type Conversion (Explicit)
You intentionally convert a value from one type to another using functions like String(), Number(), or Boolean().
// Explicit conversion - YOU control it
let num = 123;
let str = String(num); // You explicitly convert number to string
console.log(str); // "123"
console.log(typeof str); // "string"
let text = "456";
let number = Number(text); // You explicitly convert string to number
console.log(number); // 456
console.log(typeof number); // "number"Type Coercion (Implicit)
JavaScript automatically converts types behind the scenes. This happens when you use operators with mixed types.
// Implicit coercion - JavaScript does it automatically
let result = "5" + 3; // JavaScript converts 3 to "3"
console.log(result); // "53" (string)
let sum = "5" - 2; // JavaScript converts "5" to 5
console.log(sum); // 3 (number)
// This can be confusing!
console.log("5" + 3); // "53" (string concatenation)
console.log("5" - 3); // 2 (number subtraction)
console.log("5" * 3); // 15 (number multiplication)Important: Type coercion can lead to unexpected bugs. It's better to use explicit conversion so you know exactly what's happening in your code.
Converting to String
There are several ways to convert values to strings.
Using String()
// Convert numbers
console.log(String(123)); // "123"
console.log(String(3.14)); // "3.14"
console.log(String(-42)); // "-42"
// Convert booleans
console.log(String(true)); // "true"
console.log(String(false)); // "false"
// Convert null and undefined
console.log(String(null)); // "null"
console.log(String(undefined)); // "undefined"
// Convert NaN and Infinity
console.log(String(NaN)); // "NaN"
console.log(String(Infinity)); // "Infinity"Using .toString()
// Works on numbers, booleans, arrays, objects
let num = 123;
console.log(num.toString()); // "123"
let bool = true;
console.log(bool.toString()); // "true"
let arr = [1, 2, 3];
console.log(arr.toString()); // "1,2,3"
// Does NOT work on null or undefined
// null.toString(); // ❌ Error!
// undefined.toString(); // ❌ Error!
// String() is safer for these cases
console.log(String(null)); // ✅ "null"
console.log(String(undefined)); // ✅ "undefined"Template Literals (Implicit)
// Template literals automatically convert to string
let age = 25;
let message = `I am ${age} years old`;
console.log(message); // "I am 25 years old"
let isActive = true;
console.log(`Status: ${isActive}`); // "Status: true"
// This is actually implicit coercion
// But it's predictable and safeConcatenation with Empty String
// Adding empty string forces string conversion
let num = 123;
let str = num + "";
console.log(str); // "123"
console.log(typeof str); // "string"
// Works but not recommended (unclear intent)
// Better to use String() for clarityString Conversion Practice
Try different string conversion methods
console.log() to see your output in the console above.Converting to Number
Converting strings to numbers is very common, especially when dealing with user input.
Using Number()
// Convert strings to numbers
console.log(Number("123")); // 123
console.log(Number("3.14")); // 3.14
console.log(Number("-42")); // -42
// Convert booleans
console.log(Number(true)); // 1
console.log(Number(false)); // 0
// Convert null and undefined
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// Failed conversions return NaN
console.log(Number("hello")); // NaN
console.log(Number("123abc")); // NaN
console.log(Number("")); // 0 (empty string becomes 0!)
console.log(Number(" ")); // 0 (whitespace becomes 0!)Using parseInt() and parseFloat()
// parseInt - extracts integer from start of string
console.log(parseInt("123")); // 123
console.log(parseInt("123.456")); // 123 (truncates decimal)
console.log(parseInt("123px")); // 123 (stops at non-digit)
console.log(parseInt("px123")); // NaN (must start with digit)
// parseFloat - extracts decimal number
console.log(parseFloat("3.14")); // 3.14
console.log(parseFloat("3.14.15")); // 3.14 (stops at second dot)
console.log(parseFloat("10px")); // 10
// parseInt with radix (base)
console.log(parseInt("1010", 2)); // 10 (binary to decimal)
console.log(parseInt("FF", 16)); // 255 (hex to decimal)
console.log(parseInt("10", 10)); // 10 (decimal)Difference: Number() vs parseInt()
let value1 = "123px";
let value2 = " 123 ";
let value3 = "3.14";
console.log("=== Number() ===");
console.log(Number(value1)); // NaN (strict, entire string must be number)
console.log(Number(value2)); // 123 (ignores whitespace)
console.log(Number(value3)); // 3.14
console.log("\n=== parseInt() ===");
console.log(parseInt(value1)); // 123 (stops at 'p')
console.log(parseInt(value2)); // 123 (ignores whitespace)
console.log(parseInt(value3)); // 3 (truncates decimal)
console.log("\n=== parseFloat() ===");
console.log(parseFloat(value1)); // 123 (stops at 'p')
console.log(parseFloat(value2)); // 123 (ignores whitespace)
console.log(parseFloat(value3)); // 3.14 (keeps decimal)Unary Plus Operator (+)
// Unary + is a shorthand for Number()
let str = "123";
let num = +str;
console.log(num); // 123
console.log(typeof num); // "number"
// More examples
console.log(+"3.14"); // 3.14
console.log(+true); // 1
console.log(+false); // 0
console.log(+"hello"); // NaN
// Practical use
let input = "25";
let age = +input; // Quick conversion
console.log(age + 5); // 30 (not "255"!)When to use which:
Number()- When you need strict conversion (entire string must be a number)parseInt()- When extracting integers from strings like "123px"parseFloat()- When you need decimal numbers+value- Quick shorthand for Number() in simple cases
Converting to Boolean
Understanding boolean conversion is crucial because it's used in conditions and logical operations.
Using Boolean()
// Falsy values (only 6!)
console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
// Everything else is truthy!
console.log(Boolean(true)); // true
console.log(Boolean(1)); // true
console.log(Boolean(-1)); // true
console.log(Boolean("hello")); // true
console.log(Boolean("0")); // true (string!)
console.log(Boolean("false")); // true (string!)
console.log(Boolean([])); // true (array)
console.log(Boolean({})); // true (object)
console.log(Boolean(Infinity)); // trueDouble NOT Operator (!!)
// !! is shorthand for Boolean()
let value = "hello";
let bool = !!value;
console.log(bool); // true
// How it works:
// First ! converts to boolean and negates
// Second ! negates again (back to original truthiness)
console.log(!!"hello"); // true
console.log(!!0); // false
console.log(!!""); // false
console.log(!!null); // false
console.log(!![]); // true
// Practical use: ensure boolean type
let isActive = !!"yes"; // true
let isEmpty = !!""; // falseImplicit Boolean Conversion
// if statements automatically convert to boolean
let value = "hello";
if (value) { // Implicitly converted to boolean
console.log("Value is truthy");
}
// Common patterns
let username = "";
if (!username) {
console.log("Username is empty");
}
let score = 0;
if (score) {
console.log("Has score"); // Won't execute (0 is falsy)
}
// Ternary also converts
let message = username ? "Welcome" : "Please log in";Truthy and Falsy Values
See the variables, their types, and values in real-time
let falsy1 = false;
let falsy2 = 0;
let falsy3 = "";
let falsy4 = null;
let falsy5 = undefined;
let falsy6 = NaN;
let truthy1 = "hello";
let truthy2 = 1;
let truthy3 = [];
let truthy4 = {};No variables detected. Declare some variables in the code above.
let, const, or var keywords.Type Coercion with Operators
Different operators cause different type coercions. Understanding this prevents bugs.
The Plus Operator (+)
// + with strings = concatenation
console.log("5" + 3); // "53" (3 becomes "3")
console.log(5 + "3"); // "53" (5 becomes "5")
console.log("Hello" + true); // "Hellotrue"
// + with only numbers = addition
console.log(5 + 3); // 8
// Mixed - string "wins"
console.log("5" + 3 + 2); // "532" (left to right)
console.log(5 + 3 + "2"); // "82" (5+3=8, then 8+"2"="82")
// Confusing examples
console.log("5" + + "3"); // "53" (second + is unary plus)
console.log(+"5" + +"3"); // 8 (both converted to numbers)Math Operators (-, *, /, %)
// Math operators convert strings to numbers
console.log("10" - 5); // 5
console.log("10" * 2); // 20
console.log("10" / 2); // 5
console.log("10" % 3); // 1
// Both operands converted if possible
console.log("10" - "3"); // 7
console.log("10" * "2"); // 20
// If conversion fails, result is NaN
console.log("hello" - 5); // NaN
console.log("10" * "abc"); // NaN
// Tricky: - operator is different from +
console.log("5" + 3); // "53" (concatenation)
console.log("5" - 3); // 2 (subtraction)Comparison Operators
// Loose equality (==) does type coercion
console.log(5 == "5"); // true (string "5" converts to number)
console.log(0 == false); // true (false converts to 0)
console.log("" == false); // true (both become 0)
console.log(null == undefined); // true (special case)
// Strict equality (===) does NOT coerce
console.log(5 === "5"); // false (different types)
console.log(0 === false); // false (different types)
console.log("" === false); // false (different types)
// Comparison operators (<, >, <=, >=)
console.log("10" > 5); // true ("10" converts to 10)
console.log("5" < "10"); // true (string comparison!)
// ALWAYS use === and !== to avoid surprises
console.log(5 === 5); // true
console.log("5" === "5"); // true
console.log(5 === "5"); // falseBest Practice: ALWAYS use === and !== instead of == and !=. Strict equality prevents unexpected type coercion bugs.
Common Type Coercion Gotchas
String + Number Confusion
// Problem: User input is always a string
let userAge = "25"; // From an input field
let nextYear = userAge + 1;
console.log(nextYear); // "251" 😱 NOT 26!
// Solution: Convert to number first
let userAge = "25";
let nextYear = Number(userAge) + 1;
console.log(nextYear); // 26 ✅
// Or use unary plus
let nextYear = +userAge + 1;
console.log(nextYear); // 26 ✅Falsy Value Checks
// Problem: 0 is falsy
let score = 0;
if (score) {
console.log("Has score"); // Won't execute!
}
// Solution: Check explicitly
if (score !== undefined && score !== null) {
console.log("Has score"); // Executes ✅
}
// Or check type
if (typeof score === "number") {
console.log("Has score"); // Executes ✅
}
// Problem: Empty string is falsy
let name = "";
if (name) {
console.log("Has name"); // Won't execute
}
// Solution: Check length
if (name.length > 0) {
console.log("Has name");
}Array and Object Coercion
// Arrays and objects convert to strings weirdly
console.log([1, 2, 3] + [4, 5, 6]); // "1,2,34,5,6" 😕
console.log({} + {}); // "[object Object][object Object]" 😕
// Arrays to numbers
console.log(Number([])); // 0
console.log(Number([5])); // 5
console.log(Number([1, 2])); // NaN
// Empty arrays are truthy!
if ([]) {
console.log("Empty array is truthy!"); // Executes!
}
// Check array length instead
let items = [];
if (items.length > 0) {
console.log("Has items");
}Explicit is better than implicit
Relying on Coercion
// Implicit coercion (risky)
let age = "25";
let nextAge = age + 1;
console.log(nextAge); // "251" ❌
if (age == 25) { // Coercion
console.log("25!");
}
let score = "100";
let bonus = score * 1.1; // Works but unclear
console.log(bonus);Explicit Conversion
// Explicit conversion (safe)
let age = "25";
let nextAge = Number(age) + 1;
console.log(nextAge); // 26 ✅
if (age === "25") { // No coercion
console.log("25!");
}
let score = "100";
let bonus = Number(score) * 1.1;
console.log(bonus);Practical Examples
Example 1: Form Input Validation
function validateAge(input) {
// Clean the input
let cleaned = input.trim();
// Convert to number
let age = Number(cleaned);
// Check if conversion was successful
if (isNaN(age)) {
return { valid: false, message: "Please enter a valid number" };
}
// Check range
if (age < 0 || age > 150) {
return { valid: false, message: "Age must be between 0 and 150" };
}
return { valid: true, age: age };
}
console.log(validateAge("25")); // { valid: true, age: 25 }
console.log(validateAge("abc")); // { valid: false, message: "..." }
console.log(validateAge("200")); // { valid: false, message: "..." }Example 2: Price Calculator
function calculateTotal(priceInput, quantityInput) {
// Convert inputs to numbers
let price = parseFloat(priceInput);
let quantity = parseInt(quantityInput);
// Validate conversions
if (isNaN(price) || isNaN(quantity)) {
return "Invalid input";
}
// Calculate
let total = price * quantity;
// Return formatted result
return `Total: $${total.toFixed(2)}`;
}
console.log(calculateTotal("19.99", "3")); // Total: $59.97
console.log(calculateTotal("19.99", "abc")); // Invalid inputExample 3: Boolean Checks
function checkUserStatus(user) {
// Convert to booleans explicitly
let hasName = Boolean(user.name && user.name.trim());
let hasEmail = Boolean(user.email && user.email.trim());
let isActive = Boolean(user.isActive);
let hasAge = user.age !== undefined && user.age !== null;
return {
complete: hasName && hasEmail,
active: isActive,
hasAge: hasAge
};
}
let user1 = {
name: "John",
email: "john@example.com",
isActive: true,
age: 25
};
let user2 = {
name: "",
email: "test@example.com",
isActive: false,
age: 0 // 0 is valid age!
};
console.log(checkUserStatus(user1));
// { complete: true, active: true, hasAge: true }
console.log(checkUserStatus(user2));
// { complete: false, active: false, hasAge: true }Type Conversion Explorer
See how different values convert
console.log() to see your output in the console above.Type Conversion Best Practices
DO:
- Use explicit conversion:
Number(),String(),Boolean() - Always use
===and!==for comparisons - Validate user input before converting
- Check for
NaNafter number conversion withisNaN() - Use
parseInt()andparseFloat()when appropriate - Document when you intentionally rely on coercion
DON'T:
- Rely on implicit coercion unless you fully understand it
- Use
==or!=(use strict equality instead) - Assume string + number will add (it concatenates!)
- Forget that user input is always strings
- Use truthy/falsy checks when you need explicit type checks
- Convert without validating the result
Key Takeaways
- Type conversion is explicit (you do it), coercion is implicit (JavaScript does it)
- Use
String(),Number(),Boolean()for explicit conversion Number()is strict,parseInt()is lenient- Failed number conversion returns
NaN - Only 6 falsy values: false, 0, "", null, undefined, NaN
- The + operator concatenates with strings, other math operators convert to numbers
- Always use
===instead of== - User input is always strings—convert before calculations
- Use
isNaN()to check for failed conversions - Explicit conversion makes code clearer and prevents bugs
What's Next?
You now understand how JavaScript converts between types and how to control that process. This knowledge is essential for writing predictable, bug-free code—especially when working with user input and different data sources.
In the next lesson, we'll explore Operators in detail—arithmetic, comparison, logical, and assignment operators. You'll learn how to perform calculations, make comparisons, and combine conditions to make your programs more powerful and expressive!
💪 Practice Challenge:
Before moving on, try creating:
- A function that safely converts a string to a number and returns null if conversion fails
- A calculator that takes string inputs and returns the correct numeric result
- A validator that checks if a value is a valid positive integer
- A function that normalizes mixed-type arrays to all one type
- A comparison function that works correctly regardless of input types