Skip to main content

T extends never

1. What never is

The never type means:

"a value that can never exist".

Examples:

javascript
function fail(): never { throw new Error("Error!"); }

never is a subtype of all types, but nothing is a subtype of never, except never itself.


2. What T extends never ? X : Y does

This is a conditional type, which can be read as:

"If type T is never, return X, otherwise return Y."

Example:

javascript
type Check<T> = T extends never ? "YES" : "NO"; type A = Check<never>; // "YES" type B = Check<string>; // "NO" type C = Check<any>; // "NO"

A returns "YES", because T is indeed never.


3. But! A quirk: conditional types distribute over union types

If T is a union (A | B | C), TypeScript applies the condition separately to each member.

javascript
type Example<T> = T extends never ? "Y" : "N"; type R1 = Example<string | never | number>; // Step by step: // string → "N" // never → "Y" // number → "N" // R1 = "N" | "Y" | "N" → "N" | "Y"

Even if never is present inside the union, it "dissolves" (has no effect), and the result stays "N" | "Y".


4. Why never sometimes "disappears" in unions

never is an "absorbing" element of unions:

javascript
string | never // → string number | never // → number

So when substituted into T extends ..., if T doesn't exist at all (for example, after filtering), the result is not distributed and can turn into never.


Example 1: checking for an "empty" type

javascript
type IsNever<T> = [T] extends [never] ? true : false; type A = IsNever<never>; // true type B = IsNever<string>; // false type C = IsNever<any>; // false

Why square brackets? They disable distributivity, and the check runs against the type as a whole, not against each union member.


Example 2: without brackets, the result is unexpected

javascript
type IsNeverDistributive<T> = T extends never ? true : false; type A = IsNeverDistributive<never>; // never (!) - not true

Because the conditional type "distributed" over an empty set (never → no members → no result). So the result became never, not true.

Fix:

javascript
type IsNever<T> = [T] extends [never] ? true : false;

Example 3: using it to filter types

javascript
type FilterNever<T> = T extends never ? never : T; type A = FilterNever<string | never | number>; // string | number

All never values were "filtered out" of the union type.


Example 4: checking in conditional utilities

javascript
type SafeReturn<T> = T extends never ? "No value" : T; type A = SafeReturn<never>; // "No value" type B = SafeReturn<"ok">; // "ok"

The mechanics, briefly

SituationWhat happens
never extends nevertrue
never extends anything elsetrue (since never is a subtype of all types)
something extends neverfalse (except never itself)
T extends never ? X : YReturns X only if T === never
T extends never ? X : Y (with a union)Distributes over each union member
[T] extends [never] ? X : YChecks the whole type without distribution

Summary

CheckBehaviorExample
Simple checkT extends never ? X : YCheck<never>X
Unexpected distributionT = never gives never, not XIsNeverDistributive<never>never
Correct check[T] extends [never] ? X : YIsNever<never>true
FilteringT extends never ? never : TRemoves never from a union
Reasonnever is an "empty set of types"Contains no values, but is a subtype of any type

Put simply

  • T extends never ? X : Y is a conditional type for checking "emptiness".
  • But when T = never, it turns into never itself.
  • To correctly check "is the type never", you need to wrap the type in a tuple: type IsNever<T> = [T] extends [never] ? true : false;

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.