JAVASCRIPT / VALUES, TYPES, AND COERCION
Explicit conversion with Number, String, and Boolean
Convert any value to a number, string, or boolean on purpose with Number(), String(), and Boolean(), and predict what each returns for messy input.
What you will learn
- Call Number, String, and Boolean without new to get primitives, not wrapper objects
- Number("12px") is NaN but parseInt("12px") is 12, so pick by whether prefixes count
- String(null) gives "null" while null.toString() throws a TypeError
- Boolean(x) returns only true or false, using the same test an if statement uses
Understanding Explicit conversion with Number, String, and Boolean
Number, String, and Boolean are ordinary functions when you call them without new, and each one has a single job: hand back a primitive of that type for whatever you pass in. In practice they are total functions — Boolean accepts every value, String accepts every value including symbols, and Number accepts everything except symbols, which throw a TypeError. The mental model is that the conversion happens exactly where you wrote the call, with a target type you chose, instead of at some operator that decides for you further down the line.
Number treats a string as a complete numeric literal: it strips surrounding whitespace and then requires the remainder to be something JavaScript could have written as a number, such as 3.9, 1e3, 0x10, or Infinity. An empty or whitespace-only string leaves nothing to parse and is defined as 0, while anything with leftover characters, like "12px" or "1,234", has no numeric reading and becomes NaN. Non-strings follow a fixed table: true is 1, false and null are 0, undefined is NaN, and objects are asked for a primitive first, which is why [] becomes 0 and [7] becomes 7 while {} becomes NaN.
String(value) is the conversion that never leaves you holding a crash: it returns "null" and "undefined" for the empty values where value.toString() would throw, and it is the only conversion that accepts a symbol. For objects it requests a primitive with a string preference, so an array comes back as its comma-joined elements and a plain object comes back as "[object Object]". Boolean(value) collapses any value into one of exactly two results using the same rule an if uses, which matters when the answer has to be stored, returned, or compared with === rather than merely branched on.
const raw = " 42 ";
const n = Number(raw);
console.log(n, typeof n);
console.log(Number("42px"));
console.log(Number(""), Number(null), Number(undefined));
const s = String(255);
console.log(s, typeof s);
console.log(String(null), String([1, 2, 3]));
console.log(Boolean("0"), Boolean(""), Boolean(NaN));Called as plain functions, Number, String, and Boolean let you fix the target type at a chosen point in the code, each with its own fixed and memorizable conversion rules.
Worked examples
Number against parseInt on the same strings
Shows that Number validates a whole string while parseInt reads a prefix and stops.
const inputs = ["12px", "3.9", " 7 ", "", "0x10"];
for (const s of inputs) {
console.log(JSON.stringify(s), Number(s), parseInt(s, 10));
}Example explained
Line 1Number(s) demands that the entire trimmed string be a numeric literal, so "12px" has no valid reading and yields NaN.
Line 2parseInt takes as many leading digits as it can and discards the rest, giving 12 for "12px" and truncating "3.9" to 3.
Line 3Number("") is 0 because trimming leaves an empty numeric literal, while parseInt finds no digit at all and reports NaN.
Line 4With radix 10 parseInt stops at the "x" of "0x10" and returns 0, but Number recognizes the hex form and returns 16.
String() where + and .toString() give up
Demonstrates that String() is defined for null, undefined, BigInt, and symbols, unlike concatenation.
const id = Symbol("session");
console.log(String(null), String(undefined), String(12n));
console.log(String(id));
try {
console.log("id: " + id);
} catch (err) {
console.log(err.name);
}Example explained
Line 1String(null) and String(undefined) produce the words "null" and "undefined" instead of throwing, which is why they are safe for possibly-missing values.
Line 2String(12n) drops the BigInt n suffix and returns the digits "12".
Line 3String is the only conversion that accepts a symbol, so String(id) succeeds.
Line 4The + operator refuses to stringify a symbol, so the concatenation throws and err.name prints TypeError.
Boolean() and the wrapper-object trap
Shows what Boolean actually inspects and why new Boolean(false) behaves like the opposite of what it says.
console.log(Boolean("false"), Boolean("0"), Boolean([]), Boolean({}));
console.log(Boolean(0), Boolean(-0), Boolean(0n), Boolean(NaN));
const flag = new Boolean(false);
console.log(typeof flag, Boolean(flag), flag === false);
if (flag) {
console.log("the wrapper object is truthy");
}Example explained
Line 1Boolean only asks whether it received one of the falsy values, so the non-empty string "false" and the empty array both come back true.
Line 20, -0, 0n, and NaN are all falsy, so every numeric case on that line collapses to false.
Line 3new Boolean(false) builds an object wrapper, so typeof is "object", Boolean(flag) is true, and flag === false can never hold.
Line 4The if branch runs because the object, not the false it wraps, is what gets tested.
Important notes
Number understands 0x10, 0b101, 1e3, and "Infinity" but rejects units and thousands separators, so "12kg" and "1,234" are NaN; parseInt and parseFloat are prefix parsers, not validators.
String(x) and `${x}` agree on every value except symbols, where the template literal throws and String(x) returns "Symbol(...)".
Common mistakes
Writing new Number(5) or new Boolean(false): the result is an object, so 5 === new Number(5) is false and new Boolean(false) passes an if check.
Validating numeric input with Number.isNaN alone: Number("") and Number(" ") are 0, so a blank field silently turns into a quantity of zero.
Reaching for value.toString() to look explicit: it throws a TypeError as soon as value is null or undefined, which is usually the case the conversion was added for.
Try it yourself
Change, predict, then run
In a browser console, create const raw = ["", " 8 ", "8kg", null, "0", "1,234"] and log Number(v), String(v), and Boolean(v) for every entry. Then write a single condition that accepts only the entries representing a real quantity above zero, and check it against all six.
Open the JavaScript workspaceCheck your understanding
A blank text field arrives as "" and the code runs: const qty = Number(raw); if (Number.isNaN(qty)) reject(); Why does the blank field get past the check?
- Number.isNaN only recognizes NaN produced by arithmetic, not NaN produced by conversion
- Number("") returns undefined, and undefined is not NaN
- Number("") returns 0, a perfectly valid number, so the check sees nothing wrong
- The empty string is falsy, so Number never actually runs on it
Show answer
Number trims the string and then reads what is left as a numeric literal; an empty literal is defined as 0, so qty is the number 0 and the NaN guard has nothing to catch. The first option is tempting because NaN has its own quirks, but Number.isNaN does not care where a NaN came from — the real issue is that no NaN was ever produced.