To extend @Cerberus' answer and as suggested by @Paleo in the comments, all types in JavaScript except Object.create(null), null and undefined have Object as their top ancestors as shown by the following code snippet:
const arr = [{}, 1, 'hello', (a, b) => a+b, true, null, undefined, Object.create(null)];
function getPrototypeChain(value) {
const ancestors = [];
let proto = value;
while (proto) {
proto = Object.getPrototypeOf(proto);
if (proto) {
ancestors.push(proto.constructor.name);
}
};
return ancestors
}
arr.forEach(x => console.log(x, '->', getPrototypeChain(x).join(' -> ')));
From the TypeScript doc (Best Common Type, suggested by @jcalz in the comments):
When a type inference is made from several expressions, the types of those expressions are used to calculate a “best common type”.
[...]
The best common type algorithm considers each candidate type, and picks the type that is compatible with all the other candidates.
So if you use a non-empty object, no best common type will be found in the list, and since
When no best common type is found, the resulting inference is the union array type
You get a union of all item types as the result.
However, from the moment you include a single empty object in your list and you don't have any null or undefined items, Object becomes the best common type and the output will be an empty object.
{}is a common ancestor forstringandnumber.{}, which is from a time when{}was considered a top type (nowadays you'd useunknown) and when union types didn't yet exist. Not sure if that's official enough to put in an answer, though.