0 | "" | {} extends 0 | "" // false
0 | "" | {} extends 0 | {} // true
The union 0 | "" | {}
is larger than the union 0 | ""
so it technically extends from it. I am puzzled as to why it returns false.
This question is from the answer to a Typescript type-challenge AnyOf. I would appreciate if someone could breakdown the answer for me. In particular I don't understand how Typescript computes UnionA extends UnionB
to determine whether it is true or false.
The keyword was chosen to match ES6 classes: class SubClass extends BaseClass...
which means SubClass is a more specialized type.
Knowing this, one problem then become clear: 0 | "" | {}
is not a more specialized type than 0 | ""
. Instead of narrowing it down, you added more possibilities for it to handle. So it should indeed return false
.
You can test the idea of "MoreSpecific extends LessSpecific", for example: 0 | "" extends 0 | "" | {} ? true : false
(result: true).
Another approach is to think about assignments.
let variable: BaseClass = some_instance_of_SubClass
should be a valid assignment.
But if you have a value known to be of type 0 | "" | {}
and try let myVar1: 0 | "" = value;
you'll find that it's not assignable, as none of the members of the union type 0 | ""
allows you to assign {}.
As for 0 | "" | {} extends 0 | {}
leading to true, it’s because of some peculiarities of the empty object type.
You can do such assignments:
let test1: {} = ""
let test2: {} = 34
let test3: {} = {"anything you like": "other than null or undefined"}
(it is apparently done for some historical purposes, see https://github.com/microsoft/TypeScript/issues/44520 “It's a concession to back-compat because { }
was the top type when generics were introduced”)
Since you can assign anything other than null or undefined to {}
, anything other than null or undefined extends {}
.
0 | "" | {}
is assignable to type {}
as none of the values are null/undefined. Therefore, 0 | "" | {}
is assignable to type 0 | {}
. So "... extends ..." should return true.
The 'extra possibility' of ""
is already covered by the {}
part of 0 | {}
.