Suggest an editImprove this articleRefine the answer for “T extends never”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)The `never` type means "a value that can never exist" - it is a subtype of all types, but no type other than `never` itself is a subtype of `never`. **Key point:** the conditional type `T extends never ? X : Y` distributes over union types, so to correctly check whether `T` is exactly `never`, the type must be wrapped in a tuple: `[T] extends [never] ? X : Y`.Shown above the full answer for quick recall.Answer (EN)Image## 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 | Situation | What happens | | --- | --- | | `never extends never` | true | | `never extends anything else` | true (since `never` is a subtype of all types) | | `something extends never` | false (except `never` itself) | | `T extends never ? X : Y` | Returns `X` only if `T === never` | | `T extends never ? X : Y` (with a union) | Distributes over each union member | | `[T] extends [never] ? X : Y` | Checks the *whole type* without distribution | --- ## Summary | Check | Behavior | Example | | --- | --- | --- | | **Simple check** | `T extends never ? X : Y` | `Check<never>` → `X` | | **Unexpected distribution** | `T` = `never` gives `never`, not `X` | `IsNeverDistributive<never>` → `never` | | **Correct check** | `[T] extends [never] ? X : Y` | `IsNever<never>` → `true` | | **Filtering** | `T extends never ? never : T` | Removes `never` from a union | | **Reason** | `never` 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;`For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.