Reputation: 16713
Given the following:
type ArrayInfer<A> = A extends (infer I)[] ? I : never;
const a = ["foo", 1, {a: "foo"}];
type inferred = ArrayInfer<typeof a>;
My type inferred
resolves to:
type inferred = string | number | {
a: string;
}
But if I change my array slightly to include an empty object literal:
const a = ["foo", 1, {}];
Then inferred
no longer includes string
and number
in its type definition:
type inferred = {}
Why is that?
Upvotes: 4
Views: 785
Reputation: 13964
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.
Upvotes: 1
Reputation: 10218
It seems that both string
and number
are assignable to {}
: playground (in fact, every type would be assignable to {}
, except null
, void
and undefined
). So TypeScript unifies three types to the widest one. When you had the first case, there wasn't one type to use among the three ones presented, so you've had a union.
Upvotes: 2