Search code examples
javascripttemplate-literals

For which values does template string literal throws?


A simple template literal expression:

`${value}`

… will throw TypeError in at least two cases:

try {
  `${Symbol('nope')}`
} catch (error) {
  console.error(`${error.name}: ${error.message}`)
}

  • if value is an empty non-inherited object.

try {
  `${Object.create(null)}`
} catch (error) {
  console.error(`${error.name}: ${error.message}`) // weird error message in this case: "No default value"
}

What are the other cases in which it throws an error, if any? Is there some universal rule for that (like, not having some method used internally)?


Solution

  • What are the other cases in which it throws an error, if any?

    There's too many to count. Basically every object for which coercing it to a (string) primitive fails.

    Is there some universal rule for that (like, not having some method used internally)?

    Not a single method but three of them. The abstract ToString operation which is used in template literal evaluation (and everywhere else in the spec when a value needs to be coerced to a string - in particular for string concatenation, values to be used as property keys, and arguments that are expected to be strings) does

    • throw on symbols, as you noted

    • call the abstract ToPrimitive operation on objects, which in turn tries to call either

      1. o[Symbol.toPrimitive]("string")
      2. o.toString()
      3. o.valueOf()

      if the method exists. If toString returns an object, valueOf is tried as well.
      An exception is thrown if the called methods throw, or if the properties exist but have a value that is neither undefined, null, nor a function, or if none of the methods exists, or if none of the methods returned a returned a primitive (non-object) value. If the method returned a primitive value, it is fed to ToString again (which throws on symbols and returns a string otherwise).