void
and any
are not mutually exclusive: a void
is also an any
.
You can see it by doing the union betweed them. If they were exclusive, void
would not disappear to let only any
:
type T = void | any // any
Knowing that, it is normal that your IsAny
resolves to true
.
As for your IsVoid
type, it resolves to boolean
, which is actually true | false
. You can see that by changing true
and false
by something else like 1
and 2
. You will then get 1 | 2
.
This is because your any
type could be either void
or something else that is not void
. So we don't know if it extends void
or not.
To know if a type is exactly any
and nothing more special, or exactly void
and nothing less special, you can do like this (inspired from this answer):
type IsStrictAny<T> = 0 extends (1 & T) ? T : never;
type A = IsStrictAny<any> // any
type B = IsStrictAny<void> // never
type IsVoid<T> = T extends void ? T : never
type IsNotStrictAny<T> = T extends IsStrictAny<T> ? never : T
type IsStrictVoid<T> = IsVoid<T> & IsNotStrictAny<T>
type C = IsStrictVoid<any> // never
type D = IsStrictVoid<void> // void