TypeScript Version: 3.5.1
Search Terms: template string, template literal, Object.create(null)
Code
`${Object.create(null)}`
Expected behavior: TypeError, as the object passed to the template string has no toString method in the prototype chain (as it has no prototype chain at all).
Actual behavior: Everything goes well in the compiler, but JavaScript reports runtime error (ex. TypeError: Cannot convert object to primitive value in Chrome).
Playground Link: https://www.typescriptlang.org/play/index.html#code/AYEg3g8gRgVgpgYwC4DoECc4EMlwBQB2ArgDYkCUAvsEA
Related Issues:
https://github.com/microsoft/TypeScript/issues/30239
https://github.com/microsoft/TypeScript/issues/1108
It should be possible, however, to pass that weird object-not-object thingy to tagged template literal, as tag function may be able to deal with that.
interface OptionalToString {
toString?: () => string
}
function tag(_: TemplateStringsArray, value: OptionalToString) {
if (typeof value.toString !== 'function') {
return Object.prototype.toString.call(value);
}
return value.toString();
}
tag`${Object.create(null)}`;
Object.create(null) has bitten me in the past. I hate it. I don't like it when developers and libraries use it.
It's because of them, I need to do stuff like Object.prototype.hasOwnProperty.call(obj, k)
Because obj.hasOwnProperty fails for Object.create(null)
You just have to use libraries that actually support it and remember to support it, yourself.
It's not a TS problem
Because obj.hasOwnProperty fails for Object.create(null)
Actually this is usually why you would use it: because you鈥檙e using an object as a dictionary and don鈥檛 want anything from Object.prototype interfering. Admittedly it鈥檚 less useful now that we have Map but it did serve a useful purpose when it was introduced.
If you ever wondered why we have a bunch of a static methods on Object now, e.g., Object.keys, rather than them being direct instance methods鈥攖his is why.