TypeScript’s conditional types have been a wall I’ve been climbing for years. I can read them; I can’t write them. Or rather, I can copy-paste one from a Stack Overflow answer and tweak it, but I can’t reason from first principles about what a given conditional will do.
The breakthrough came from sitting with one specific behaviour: distribution. When you write T extends U ? X : Y and T is a union, the conditional distributes — it evaluates element-wise across the union and unions the results. So Exclude<'a' | 'b' | 'c', 'b'> isn’t ‘is the whole union assignable to 'b'?’, it’s three separate checks, each producing either the type or never, and never disappears from a union.
Once that clicked, the rest of the standard library made sense. Extract, NonNullable, every variant I’d memorised — they’re all the same trick, leaning on the fact that never is the union identity element.
I wrote a tiny helper to make it concrete: type Distribute<T> = T extends any ? [T] : never. Apply it to a union and you get a union of single-element tuples, which is useful occasionally but more importantly is a clear, debuggable demonstration of distribution. I’ve put it in my mental toolbox next to console.log.
The wider lesson: when something in a type system feels mystical, there’s usually a single mechanical rule underneath that you haven’t named yet. Find the rule.