A simple template literal expression:
`${value}`
… will throw TypeError in at least two cases:
- if
valueis a Symbol;
try {
`${Symbol('nope')}`
} catch (error) {
console.error(`${error.name}: ${error.message}`)
}
- if
valueis 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)?
There's too many to count. Basically every object for which coercing it to a (string) primitive fails.
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
o[Symbol.toPrimitive]("string")o.toString()o.valueOf()if the method exists. If
toStringreturns an object,valueOfis 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).