A simple template literal expression:
`${value}`
… will throw TypeError
in at least two cases:
- if
value
is a Symbol;
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)?
2
Answers
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 obects, which in turn tries to call
o[Symbol.toPrimitive]("string")
o.toString()
o.valueOf()
if these methods exist, until one of them throws or returns a non-object value, which then is fed to ToString. It also throws if none of these properties are methods.
${value}
is perhaps an oversimplication of${expression}
, whereexpression
is a Javascript expression that is first evaluated, and then converted to a string to be inserted in the template.It will throw if the result of the expression doesn’t support a
toString
method:toString
operations while other primitive data types do.toString
method from their inheritance chain will also throw because calling theirtoString
method fails. Classic examples of this kind are either created byObject.create(null)
, or inherit from such an object with notoString
methods defined in the inheritance chain. E.G.It will also fail if the expression provided throws because of JavaScript errors. E.G.