Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript never type inconsistently matched in conditional type?

Tags:

typescript

In the following code you notice that the type of Result1 is never, yet the type of test3 is []. I can't make sense of this. Why are the results not the same, considering that they are both reading the never type from MyEvents?

type EventArgs<EventTypes, K extends keyof EventTypes> =
    EventTypes[K] extends never /* CHECK NEVER */
        ? []
        : EventTypes[K] extends any[]
            ? EventTypes[K]
            : [EventTypes[K]];

type foo<T> = T extends never /* CHECK NEVER */ ? [] : [boolean]
type Result1 = foo<MyEvents['anotherEvent']> // HERE, type is `never`

type MyEvents = {
    anotherEvent: never // event has no args
}

type Result2 = EventArgs<MyEvents, 'anotherEvent'> // HERE, type is `[]`

playground link

like image 507
trusktr Avatar asked Dec 31 '18 07:12

trusktr


1 Answers

What you really are asking is:

type Foo = never extends never ? true : false // gives true
//but
type Bar<T> = T extends never ? true : false
type Baz = Bar<never> // not `true` as expected but `never`!

Well, I became curious on this and wondered if it has something to do with distributive conditional types.

So I changed the above code to this:

type Bar<T> = [T] extends [never] ? true : false
type Baz = Bar<never> // true as expected

Hence the answer is: You are distributing an empty union aka never and this gives a result of the distribution of an empty union (aka never): that is another empty union! Completely makes sense!

UPD: why never is an "empty union"? Well maybe this code will demonstrate it:

type Union1 = number | string | never // number | string
type Union2 = number | never // number
type Union3 = never // never aka empty union
like image 85
Nurbol Alpysbayev Avatar answered Nov 07 '22 23:11

Nurbol Alpysbayev