Yuzhe's Blog

yuzhes

IsNever

IsNever

Challenge Link

Challenge

Implement a type IsNever, which takes an input type T. If the type resolves to never, return true, otherwise false.

type A = IsNever<never>     // expected to be true
type B = IsNever<undefined> // expected to be false
type C = IsNever<null>      // expected to be false
type D = IsNever<[]>        // expected to be false
type E = IsNever<number>    // expected to be false

Solution

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

One line. Deceptively simple. The magic is all in those square brackets.

Deep Dive

Why can’t we just write T extends never?

// ❌ Broken
type IsNeverWrong<T> = T extends never ? true : false

type Test = IsNeverWrong<never> // never, not true!

The result is never, not true. What’s going on?

Distributive conditional types strike again

When you write T extends Constraint ? A : B with a naked type parameter, TypeScript treats unions specially. It distributes the condition over each member of the union:

type Distributed = (string | number) extends string ? 'yes' : 'no'
// Becomes:
// (string extends string ? 'yes' : 'no') | (number extends string ? 'yes' : 'no')
// = 'yes' | 'no'

Now here’s the catch: never is the empty union — a union with zero members. When you distribute over nothing, you get nothing back:

// T = never (empty union)
// Distributing: ... over zero members ...
// Result: never (union of zero results)

The conditional is never evaluated at all. TypeScript short-circuits and returns never.

The tuple wrapper trick

Wrapping T in a tuple [T] disables distribution:

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

Now [T] is not a naked type parameter — it’s a tuple type containing T. TypeScript doesn’t distribute over tuple types, so the condition is evaluated exactly once:

Why does [never] work but never doesn’t?

ExpressionBehavior
never extends neverDistribution over empty set → never
[never] extends [never]Single comparison → true

The tuple acts as a container that “solidifies” the type, preventing the special empty-union behavior.

Common patterns that use this trick

// Detect never
type IsNever<T> = [T] extends [never] ? true : false

// Prevent distribution over any union
type NoDistribute<T> = [T] extends [T] ? T : never

// Safe comparison without distribution
type Equals<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false

Note that [any] extends [never] is boolean, not true or false:

type Test = [any] extends [never] ? true : false // boolean

This is because any is both assignable and not assignable to everything — TypeScript hedges and returns both branches as a union. If you need IsNever that also rejects any, you’d need an additional check:

type IsStrictNever<T> = [T] extends [never]
  ? (0 extends (1 & T) ? false : true)  // reject any
  : false

But for most use cases, the simple [T] extends [never] is sufficient.

Key Takeaways