When I see someone calling someVar.toString(), I usually advise them to use String(someVar)1 instead, as it handles null and undefined cases gracefully (depending on the definition of gracefully, of course) instead of throwing2.
For the longest time I was under the impression that calling String(someVar) would never throw, for any value of someVar. However, I was wrong. There are two cases where it also throws:
- When passed an object whose
Symbol.toPrimitiveexists but isn’t callable or calling it with'string'as first argument returns a non-primitive or throws. - When passed an object that doesn’t have a
Symbol.toPrimitiveproperty andtoStringorvalueOfeach either don’t exist, aren’t callable, return a non-primitive, or throw.
Most likely you’ll encounter the case where none of these methods are declared when handling an object that doesn’t have a prototype, e.g. if it was created using Object.create(null). In that case, my advice wouldn’t have been better or worse because both approaches throw.
But we can also craft an object specifically to throw when passed to String but not when calling toString on it:
In this case, my initial advice would be completely wrong and toString would have been the better option.
Of course, we could also easily have crafted the opposite:
I stand by the stance that String(someVar) is usually the better approach in real-world scenarios (it also looks nicer) but I’ve come around to thinking that being explicit about null and undefined is better than being implicit so I always advice for having null checks anyway.
Investigating this also helped me clear up another misconception. The String construction (when used as a function) doesn’t just apply the abstract operation ToString as defined by ECMAScript.
ToString is specified as follows:
But I already knew that String(Symbol('a')) doesn’t throw, so something else must be going on there.
The specification of String(value) clarified things:
That’s it, symbols are special-cased in String(value), they won’t ever throw!
But symbols will throw when used in an untagged template string literal as there, the ToString operation is used.


Top comments (0)