8

I want to create a type with a condition based on never but I the results are unexpected (Typescript version 4.1.3).

type TypeCond<T, U> = T extends never ? {a: U} : {b: U};

let test: TypeCond<never, number>;

I have the TypeCond that has a simple condition if T extends never.

I would expect that the type of the test variable will be {a: number} but actually, the type is never.

I'm not sure why... If I replace the never with undefined or null it works as expected. But I need the condition for the never type.

Any idea why test gets a never type instead of {a: number}?

nrofis
  • 8,975
  • 14
  • 58
  • 113
  • related: https://stackoverflow.com/questions/60869412/inferring-nested-value-types-with-consideration-for-intermediate-optional-keys – ford04 Dec 29 '20 at 14:16

1 Answers1

17

I believe this is a consequence of the distributive property of conditional types in Typescript. Essentially, (S | T) extends A ? B : C is equivalent to (S extends A ? B : C) | (T extends A ? B : C), i.e. the conditional type distributes over the union in the extends clause. Since every type T is equivalent to T | never, it follows that

  • T extends A ? B : C is equivalent to (T | never) extends A ? B : C,
  • Which in turn is equivalent to (T extends A ? B : C) | (never extends A ? B : C),
  • This is the same as the original type unioned with never extends A ? B : C.

So a conditional type of the form never extends A ? B : C must evaluate to never, otherwise the distributive property would be violated.


To make your type work as intended, you can use this trick:

type TypeCond<T, U> = [T] extends [never] ? {a: U} : {b: U};

This avoids the conditional type distributing over T, since [T] is not a "naked type parameter".

kaya3
  • 47,440
  • 4
  • 68
  • 97
  • 2
    Good explanation. It is called ["empty union"](https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379094672) by the developers. – ford04 Dec 29 '20 at 14:15