The double at sign (@@
) represents a "well-known symbol". The "[@@toPrimitive]()
" well-known symbol (introduced in ES6) denotes "Symbol.toPrimitive()
", which is used for specifying a class/object method that returns a primitive representation of an object. The Symbol.toPrimitive()
method is called with a string argument "hint
", which is equal to one of the following values:
"number"
: suggests the method was called as a result of a numeric coercion algorithm;"string"
: suggests the method was called as a result of a string coercion algorithm;"default"
: suggests the method was called as a result of a primitive coercion algorithm.
"[@@toPrimitive]()
" has great browser support, so you can implement it in your code with ease of mind.
A "Symbol.toPrimitive()
" method is the first object method that's called by all type coercion algorithms. Therefore, it can be used to convert an object to a primitive value.
For example, you can implement it in an object literal like so:
// ES6+
const obj = {
[Symbol.toPrimitive](hint) {
if (hint === 'number') {
return 1234;
} else if (hint === 'string') {
return 'foo';
}
return 'default';
}
}
console.log(Number(obj)); // 1234
console.log(+obj); // 1234
console.log(String(obj)); // 'foo'
console.log(`${obj}`); // 'foo'
console.log(obj + ''); // 'default'
Similarly, you can implement it as a class method in the following way:
// ES6+
class Foo {
[Symbol.toPrimitive](hint) {
if (hint === 'number') {
return 1234;
} else if (hint === 'string') {
return 'foo';
}
return 'default';
}
}
const foo = new Foo();
console.log(Number(foo)); // 1234
console.log(+foo); // 1234
console.log(String(foo)); // 'foo'
console.log(`${foo}`); // 'foo'
console.log(foo + ''); // 'default'
Using the "hint
" parameter is not required. Therefore, you may implement a "Symbol.toPrimitive()
" method without using it:
// ES6+
const obj = {
[Symbol.toPrimitive]() {
return 'foo';
}
}
console.log(Number(obj)); // NaN
console.log(+obj); // NaN
console.log(String(obj)); // 'foo'
console.log(`${obj}`); // 'foo'
console.log(obj + ''); // 'foo'
The reason coercion to number results in NaN
(in the example above) is because the resulting value from Symbol.toPrimitive()
method is a non-numeric value. On the flip side, if you return a number for string coercion, it will automatically coerce it to a numeric string:
// ES6+
const obj = {
[Symbol.toPrimitive]() {
return 1234;
}
}
console.log(Number(obj)); // 1234
console.log(+obj); // 1234
console.log(String(obj)); // '1234'
console.log(`${obj}`); // '1234'
console.log(obj + ''); // '1234'
The "Symbol.toPrimitive()
" method must always return a primitive or a TypeError
is thrown.
Below is an example of "Symbol.toPrimitive()
" method returning a non-primitive value, which results in a TypeError
being thrown:
const obj = {
[Symbol.toPrimitive]() {
return {};
}
}
// TypeError: Cannot convert object to primitive value
console.log(+obj);
This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.