Engrain by ByteRush

JS.05.02 Mid-level· 10 minCore — asked often

Type coercion and ToPrimitive: how JavaScript converts values for you

When types do not match, JavaScript converts them to numbers, strings or booleans. Learn the rules, why + is special, and how objects become primitives.

Comes up in: JavaScript, Recruiter screen

Learn#

Ishaan’s cart adds a delivery fee read from a form field: subtotal + fee. With a ₹500 subtotal and a ₹40 fee, the page shows ₹50040. Form fields hold strings, and + with a string joins text instead of adding.

When an operator gets the “wrong” type, JavaScript converts it for you. That is coercion — implicit conversion, because you did not ask for it.

There are three targets. ToNumber (used by -, *, <, unary +): "" → 0, " 42 " → 42, "4px" → NaN, null → 0, undefined → NaN. ToString (used by + with a string and by template literals). ToBoolean (used by if, !, &&): only false, 0, -0, 0n, "", null, undefined and NaN are false — everything else, even "0" and [], is true.

Objects are first turned into a primitive with ToPrimitive, guided by a hint: "number", "string" or "default". An object can decide for itself with Symbol.toPrimitive:

console.log([1 + "2", "3" * "4", true + 1, [] + [], [] + {}, `${[1, 2]}`]);
const price = { [Symbol.toPrimitive](hint) { console.log("hint:", hint); return hint === "string" ? "₹99" : 99; } };
console.log(+price);
console.log(`${price}`);
console.log(price + 1);

Output (verified)

[ '12', 12, 2, '', '[object Object]', '1,2' ]
hint: number
99
hint: string
₹99
hint: default
100

Without it, the default tries valueOf() then toString(). Arrays and plain objects return themselves from valueOf, so toString wins: [] → "", {} → "[object Object]".

Template literals always use the string hint.

Why [] + {} is '[object Object]'Step 1 of 4

left

  • []

right

  • {}

result

    empty

    [] + {}: + needs primitives first. Each side goes through ToPrimitive with the hint 'default'.

    Read the steps as text
    1. [] + {}: + needs primitives first. Each side goes through ToPrimitive with the hint 'default'.
    2. [].valueOf() returns the array itself — not a primitive. So toString() is tried: ''.
    3. {}.valueOf() is also the object. {}.toString() gives '[object Object]'.
    4. One side is a string, so + joins strings instead of adding numbers.

    Predict#

    Predict first

    What does this print? Type it exactly.

    console.log("5" - 2, "5" + 2);

    Interview angle#

    Say it like this — about 30 seconds

    “Coercion converts values when an operator needs a different type. Arithmetic and comparisons use ToNumber, conditions use ToBoolean, and plus joins strings if either side is a string after conversion. Objects first go through ToPrimitive with a hint: Symbol.toPrimitive if defined, otherwise valueOf then toString — or the reverse for the string hint. That is why [] + {} is ‘[object Object]’: both become strings. I convert explicitly at boundaries, like form input.”

    Stays on your device. Nothing is uploaded.
    Follow-up What does [] + {} evaluate to and why?
    ’[object Object]’. Both go through ToPrimitive; valueOf returns the objects themselves, so toString gives ” and ‘[object Object]’, and + joins them.
    Follow-up Which values are falsy?
    false, 0, -0, 0n, "", null, undefined and NaN. Everything else is truthy, including “0”, “false”, [] and .
    Follow-up How do you convert a form value to a number safely?
    Number(value) and then check Number.isNaN — or Number.parseFloat if trailing units are allowed. Do not rely on + with strings.

    Practice#

    On your own

    Give Money a Symbol.toPrimitive method so it formats as text but calculates as rupees.

    Done when

    • `${new Money(1250)}` and "Total: " + new Money(1250) give "₹12.50"-style text.
    • +m, m * 2 and m > 10 use the rupee number.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    When does + join strings instead of adding?

    When either side is a string after ToPrimitive.

    List the falsy values.

    false, 0, -0, 0n, '', null, undefined, NaN.

    What does ToPrimitive try for a plain object with the default hint?

    valueOf, then toString (unless Symbol.toPrimitive is defined).

    What does this print?
    console.log(Number(""), Number("4px"), Number(null));
    0 NaN 0

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    Three conversions — to number, to string, to boolean — and one step before them for objects: ToPrimitive. + is the only arithmetic operator that prefers strings.

    Check yourself: Is the string '0' truthy?

    Yes. Only the empty string is falsy.

    How it works underneathSenior rounds

    ToPrimitive calls Symbol.toPrimitive if present; otherwise OrdinaryToPrimitive tries valueOf then toString for “number”/“default”, and toString then valueOf for “string” Source: ECMA-262: ToPrimitive. The + operator applies ToPrimitive to both sides, then joins strings if either is a string Source: ECMA-262: ApplyStringOrNumericBinaryOperator.

    Check yourself: What order does OrdinaryToPrimitive use for the string hint?

    toString first, then valueOf.

    Edge cases and trapsWhere people slip

    Date treats the default hint as “string”, so date + 1 joins text while date - 0 gives milliseconds. Symbol values throw when converted to a string implicitly. BigInt and Number cannot be mixed in arithmetic: 1n + 1 throws a TypeError (JS.05.04).

    Check yourself: Which built-in object uses the string hint for +?

    Date.

    In productionStaff-level answers

    Convert at the edges: parse form and query values once with Number(...) and validate. TypeScript allows string + number, so add the @typescript-eslint/restrict-plus-operands rule, and use Intl.NumberFormat for display (JS.05.04).

    Check yourself: Which TypeScript setting stops adding a number to a string by accident?

    None by default — use explicit conversion and lint rules like restrict-plus-operands.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • What does [] + {} evaluate to and why?