Yuzhe's Blog

yuzhes

19749 · IsEqual

19749 · IsEqual

Challenge Link

Problem

Implement a type IsEqual<A, B> that returns true if A and B are exactly the same type, and false otherwise.

type cases = [
  Expect<Equal<IsEqual<1, 2>, false>>,
  Expect<Equal<IsEqual<never, never>, true>>,
  Expect<Equal<IsEqual<1, 1>, true>>,
  Expect<Equal<IsEqual<string, number>, false>>,
]

Solution

type IsEqual<A, B> =
  (<T>() => T extends A ? 1 : 2) extends
  (<T>() => T extends B ? 1 : 2)
    ? true
    : false

Explanation

This is the canonical TypeScript trick for strict type equality. It exploits a subtle behavior of conditional type assignability checking.

Why not just A extends B ? B extends A ? true : false : false?

That naive approach fails for several edge cases:

The trick:

TypeScript’s assignability checker for two generic functions (<T>() => T extends X ? 1 : 2) is compared structurally. Two such types are considered identical only if X in both positions is the exact same type — TypeScript does not apply conditional type distribution or any-widening here.

So (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) holds if and only if A and B are identical types.

Key insight: This pattern works because the assignability check on the deferred conditional type checks the type parameter X invariantly — it must match exactly, not just be a subtype.