TypeScript strange type behavior on extends in generic

This is a result of applying a distributive conditional type to never. If a distributive conditional type is applied to a union, the result will be a union of applying that conditional type to each constituent of the union:

type IfExtends<T> =  T extends number ? "Y" : "N"
type A = IfExtends<number | string> // = IfExtends<number> | IfExtends<string> = "Y" | "N"

So what does this have to do with never? We can get a hint if we try to union never with any other type:

type X = never | number // just number, never is omitted

never is the empty union, ie the union with no constituent. Adding it to any other union will make it melt away because of this.

Because it is the empty union, when distributing over it, the conditional type actually never get evaluated, since there are no constituents in the union to apply it to, and we just get never regardless of any condition in the conditional type

Using the actual inlined version does not produce the same result as distributivity only happens over naked type parameters, T is a naked type parameter, keyof empty is not.

You can disable distributivity by encasing T in a tuple type:

type IfExtends<T, B, Y, N> = [T] extends [B] ? Y : N
let a: IfExtends<keyof empty, never, number, string> /// also numberkeyof empty 

Playground Link

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top