Context-sensitive formatting
An object should display a formatted value in string contexts but retain a raw numeric value in arithmetic.
JS Puzzles · Const
Symbol.toPrimitive is a well-known symbol used to define an object's conversion to a primitive. JavaScript calls the associated method with a hint before falling back to valueOf() and toString().
When an object must become a primitive, JavaScript first checks for a method under Symbol.toPrimitive and passes it a hint: "string", "number", or "default". The method may choose how to interpret that hint, but it must return a primitive; otherwise conversion throws a TypeError. If the method is absent, JavaScript falls back to valueOf() and toString() according to the conversion context.
obj[Symbol.toPrimitive] = function(hint) { /* return a primitive */ };| Name | Type | Description |
|---|---|---|
hint | string | A hint indicating the preferred primitive context: "string", "number", or "default". |
A primitive value chosen by the conversion hook; returning a non-primitive causes a TypeError.
const price = {
value: 19.99,
[Symbol.toPrimitive](hint) {
return hint === "string" ? `$${this.value}` : this.value;
},
};
console.log(`${price}`); // "$19.99"
console.log(price + 1); // 20.99The same object supplies different primitive representations for string and numeric contexts.
An object should display a formatted value in string contexts but retain a raw numeric value in arithmetic.
A domain object needs predictable behavior when used with operators or interpolation.
A library exposes objects that should convert to a stable primitive representation.
JavaScript calls obj[Symbol.toPrimitive](hint) before the fallback methods. The hint is "string", "number", or "default", and the hook must return a primitive.
Follow-up: What happens when the hook is missing? JavaScript uses toString() first for a string hint, and valueOf() first for number or default hints.
The hook receives a preferred conversion context, but it can return any primitive representation it chooses. The returned type does not have to match the hint.
Follow-up: Why can one object behave differently in template literals and arithmetic? Each operation supplies a different hint, which the hook can handle separately.
The hook has priority over valueOf() and toString(). If it exists, JavaScript uses it for all primitive conversions instead of proceeding to those fallback methods.
Follow-up: What must the hook return? A primitive value; returning an object results in a TypeError.
valueOf()toString()SymbolDate