Search code examples
javascriptecmascript-6primitive-typescoercion

Symbol string coercion


Symbol() + '' throws

TypeError: Cannot convert a Symbol value to a string

While a known workaround is to use String(Symbol()).

This looks inconsistent with other primitives, including the ones that should almost never be coerced (undefined and null).

How exactly does String differ from + '' (except it works)? Do specs explicitly specify that String should accept symbols? What were the motives to allow it in one way and disallow it in another?


Solution

  • How exactly does String differ from + '' (except it works)? Do specs explicitly specify that String should accept symbols?

    They differ in the aspect that String() has a case for a Symbol(), whereas the + operator (when used for concatenation) directly calls the ToString() operation which throws a TypeError exception for a Symbol().

    From String() spec:

    If NewTarget is undefined and Type(value) is Symbol, return SymbolDescriptiveString(value).

    From + evaluation spec:

    If Type(lprim) is String or Type(rprim) is String, then

    • Let lstr be ToString(lprim).
      • ReturnIfAbrupt(lstr).
      • Let rstr be ToString(rprim).
      • ReturnIfAbrupt(rstr).
      • Return the String that is the result of concatenating lstr and rstr.

    Note: the definitions for lprim and rprim come from 10 previous steps in the evaluation process, which involve getting primitive types and values of the sides of the expression. I didn't include them to keep this post shorter. I have linked each specification I have referenced below.

    From the ToString() output:

    Symbol: Throw a TypeError exception.

    As for your final question:

    What were the motives to allow it in one way and disallow it in another?

    That's something for the writers at ECMA International.

    String() ES6 Spec

    + operator runtime evaluation ES6 Spec

    ToString() Output behavior ES6 Spec