Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~24 min· topic 5 of 6

Topic 1.5

Type Conversion

In one line

JavaScript converts values between types either when you ask (String(), Number(), Boolean(), parseInt, parseFloat) or automatically when an operator needs a different type; knowing the automatic rules prevents bugs like "5" + 1 giving "51".

Think of it like this

Changing money at an airport. You hand over rupees and ask for dollars: that's an explicit exchange, you chose it. But some shops quietly convert your money at their own rate when you pay with a card abroad: that's implicit, it happens without you asking, and the result can surprise you. JavaScript converts values between types in both ways.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Type conversion
Turning a value of one type into another, like "42" into 42.
Explicit conversion
Converting on purpose with String(), Number(), Boolean() and similar.
Coercion
Automatic conversion JavaScript does because an operator needs a different type.
parseInt
Reads a whole number from the start of a string and stops at the first non-digit.
parseFloat
Like parseInt but keeps the decimal part.
Radix
The number base: 10 for normal numbers, 16 for hexadecimal, 2 for binary.
Falsy
A value that becomes false when converted to boolean, like 0 or "".
Truthy
Any value that becomes true when converted to boolean.
Unary plus
A + in front of one value, like +"42", which converts it to a number.

Step by step

01Read a number from a form

Values from inputs are always strings, even when the input shows a number. Adding to them joins text.

app.jswhole filejavascript
const raw = qtyInput.value; // "5" (a string!)
raw + 1                    // "51"
Number(raw) + 1            // 6

02Choose Number() or parseInt()

Number is strict about the whole string. parseInt and parseFloat read from the left and stop.

app.jswhole filejavascript
Number("42")      // 42
Number("42px")    // NaN
parseInt("42px", 10) // 42
parseFloat("1.5em")  // 1.5
Number("")        // 0   (careful!)
parseInt("", 10)  // NaN

03Convert to text

String() never throws for ordinary values, and gives readable text for primitives. Objects need a better plan, like JSON.stringify (Topic 6.6).

app.jswhole filejavascript
String(3.5)        // "3.5"
String(null)       // "null"
String([1, 2, 3])  // "1,2,3"
String({ a: 1 })   // "[object Object]"

04Know what + does

JavaScript decides what + means by looking at both sides after turning objects into primitives.

Know what + doesdiagram
Rendering diagram…

05Other maths operators always want numbers

-, *, / and % convert both sides with the Number() rules, so text that isn't a clean number gives NaN.

app.jswhole filejavascript
"10" - "4"   // 6
"10" * 2     // 20
"ten" * 2    // NaN
true + true  // 2

06Convert at the edges

Convert input once, when it enters your program, and check the result (Number.isNaN). After that, every variable holds the type you expect and + behaves.

Try it yourself

  1. 1

    Predict the joins

    Before running the third example, add console.log("2" + 2 * "2");. Hint: * happens before +. Write your prediction, then run.

  2. 2

    Blank input

    In the form example, clear the box completely and press the button. It says Next: 1. Why? (Look at what Number("") returns in the first example.) How would you treat an empty box as an error?

  3. 3

    Number vs parseInt

    In the second example, try Number("1e3") and parseInt("1e3", 10). Explain the difference.

Code & diagrams

Explicit conversion with String, Number and Boolean New tab

Console

(nothing was printed)

Expected console output

42 true null undefined
1,2,3 [object Object]
ff 101
42 12 0 NaN
1 0 0 NaN
26 0 5 NaN
3.5
false true false true true
true false
parseInt and parseFloat read from the left New tab

The last line is a classic trap: the number becomes the string `"5e-7"` first, and parseInt stops at the `e`.

Console

(nothing was printed)

Expected console output

12
3.14
3
NaN
42 NaN
255 5
5
Implicit coercion with operators New tab

In the last line, `+"a"` is `NaN`, which is then joined as text.

Console

(nothing was printed)

Expected console output

51
4
12
33
123
2
1 NaN
[object Object]
baNaNa
Form values are strings New tab

Type a different number (or a word) in the box and press the button. The `? :` used here is the ternary operator from Topic 2.3.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

string
51
6

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Add two form values without converting

In a calculator, write out.textContent = a.value + b.value; with the inputs 2 and 3.

terminal
$ the page shows
── what you'll see ──
23

Break #2

Forget the radix

Use parseInt(input) on inputs like "0x10".

terminal
$ Console
── what you'll see ──
16

Myth vs fact

Myth

Number("") is NaN because the string is empty.

Fact

It's 0. Empty and whitespace-only strings convert to 0, which is why a blank form field can silently become 0. Check for empty input separately.

Myth

parseInt rounds decimals.

Fact

It truncates: it stops reading at the ., so parseInt("3.99", 10) is 3. Use Math.round(Number(x)) to round.

Myth

The string "false" is false.

Fact

Every non-empty string is truthy, including "false" and "0". Compare the text instead: value === "true".

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    ToPrimitive with hint "number" calls valueOf() then toString(); with hint "string" (template literals, String()), toString() first. + and == use the "default" hint, which behaves like "number" except for Date objects, which prefer strings. An object can override all of this with a Symbol.toPrimitive method.

  • ▸

    Number() and unary + accept 0x, 0o, 0b prefixes, Infinity, exponent notation and surrounding whitespace, but not numeric separators: Number("1_000") is NaN. Underscores are allowed only in number literals in code.

  • ▸

    Unary + throws on a BigInt (+10n is a TypeError), but Number(10n) works. That's one of the few places where +x and Number(x) differ.

  • ▸

    Coercion is spec-defined and predictable, not random: the abstract operations ToString, ToNumber, ToBoolean and ToPrimitive in the ECMAScript spec define every case. Linters (ESLint) and TypeScript catch most accidental coercion before it ships.

Remember this

  1. 1

    Type conversion means turning a value of one type into another, like the string "42" into the number 42. When you do it on purpose it's explicit conversion. When JavaScript does it automatically because an operator needs a certain type, it's implicit conversion, usually called coercion. There are only three target types that matter: string, number and boolean.

  2. 2

    To string: String(value) works on everything: String(42) is "42", String(null) is "null", String([1, 2]) is "1,2", and a plain object becomes "[object Object]", which is almost never what you want. Template literals convert the same way. Numbers also have toString(base): (255).toString(16) is "ff".

  3. 3

    To number: Number(value) reads the whole string or fails. Spaces at the ends are ignored, an empty or blank string becomes 0, and anything with stray characters becomes NaN: Number("12px") is NaN. true becomes 1, false and null become 0, undefined becomes NaN. The unary plus +value does exactly the same as Number(value). Everything you read from a form field (input.value) is a string, so you must convert it before doing maths.

  4. 4

    parseInt(string, radix) and parseFloat(string) are more forgiving: they read digits from the start and stop at the first character they don't understand. parseInt("12px") is 12, parseFloat("3.14abc") is 3.14, parseInt("3.99") is 3 (it cuts, it doesn't round). If no digits come first, the result is NaN. The radix is the number base: always pass 10 for normal numbers (parseInt("08", 10)), or 16 for hex, 2 for binary. Use Number() when the whole input must be a valid number, and parseInt/parseFloat when you want to pull a number off the front of text like "20px".

  5. 5

    To boolean: Boolean(value) returns false for exactly eight falsy values (false, 0, -0, 0n, "", null, undefined, NaN) and true for everything else, including "0", "false", " ", [] and {}. Writing !!value (not-not) is a common short form. Topic 1.6 uses these rules for if conditions.

  6. 6

    Implicit coercion follows operator rules. The + operator joins if either side is a string, so "5" + 1 is "51" and 1 + 2 + "3" is "33" (left to right: 1 + 2 is 3, then 3 + "3" joins). The other maths operators (-, *, /, %) only work on numbers, so they convert both sides: "5" - 1 is 4, "3" * "4" is 12. Objects are first turned into a primitive (a step called ToPrimitive, which calls the object's valueOf() and toString() methods): that's why [] + {} is "[object Object]". The safe habit: convert explicitly at the edges of your program (form inputs, URLs, API data), then work with the right types inside.

Explain it without notes

01

What is the difference between explicit conversion and coercion? Give an example of each.

02

When would you use Number() and when parseInt()/parseFloat()?

03

Explain the outputs of "5" + 1, "5" - 1 and 1 + 2 + "3".

04

Which values are falsy?

Practice

01

Convert the strings "19.5" and "0.5" to numbers and log their sum, which must be 20.

02

Read the width out of "240px" as a number, double it, and log 480px.

03

Predict, then check: "7" * "6", "7" + "6", "7" - - "6".

Trade-offs

  • ↔

    Explicit conversion is longer to write but makes intent obvious and catches bad input early; relying on coercion is shorter but hides bugs until a string sneaks in.

  • ↔

    Number() rejects partial input (safer for validation), parseFloat tolerates units (handier for CSS values); pick by whether stray characters should be an error.

Done when you can

  • I can convert values with String(), Number() and Boolean().

  • I can choose between Number() and parseInt/parseFloat, and I always pass a radix.

  • I can predict what +, - and * do with strings.

  • I convert form input to numbers before doing maths.

  • I can list the falsy values.