Home > Blockchain >  When comparing any to void why is the type a union?
When comparing any to void why is the type a union?

Time:10-30

I wanted to check if a supplied type was void and was surprised to find that when passing in any a union is returned. Could someone please explain why this is?

type test<T> = T extends void ? void extends T ? 1 : 0 : 0;

type v1 = test<any>; // 1 | 0
type v2 = test<unknown>; // 0
type v3 = test<undefined>; // 0
type v4 = test<null>; // 0
type v5 = test<never>; // never
type v6 = test<void>; // 1
type v7 = test<boolean>; // 0
type v8 = test<string>; // 0
type v9 = test<number>; // 0
type v10 = test<'void'>; // 0
type v11 = test<{}>; // 0

Playground

CodePudding user response:

See microsoft/TypeScript#40049 for an authoritative answer. When any is checked via a conditional type, the result will be the union of both the true and false branches. This may be surprising, but it is working as intended.

Relevant comment:

This isn't especially well-documented outside of the source-code, but in the checker you'll find in the relevant place:

// Return union of trueType and falseType for 'any' since it matches anything
if (checkType.flags & TypeFlags.Any) {

So any is treated like a wildcard that matches both branches.

CodePudding user response:

I think I managed to understand this:

void extends any ? 1 : 0 resolves to 1, meaning void does extend any. I imagine this is a design decision from Typescript authors, I wasn't able to find the reason for this. From my tests - all types extend any (checked with {}, () => 1, "v", 3, unknown).

Then, any extends void ? 1 : 0 resolves to 1 | 0 which actually makes sense (it would be one of the two types in the conditional type).

As a result

 ==> test<any>
     === any extends void ? void extends any ? 1 : 0 : 0
     === any extends void ? 1 : 0
     === 1 | 0

Playground

  • Related