Skip to the solution
HardFrontend11 min read

Why are conditional types distributive and how do you control it with infer?

624 views

The problem

Question presented to candidate: "type ToArray<T> = T extends unknown ? T[] : never gives string[] | number[] for string | number, not (string | number)[]. Why? How do you turn that off, and how does infer behave when the input is a union?"

What a strong answer should cover:

  • Distribution: when the checked type is a naked type parameter instantiated with a union, the conditional type is applied to each member separately and the results are unioned (documented since TypeScript 2.8)
  • Only a bare type parameter distributes: a union written inline, or T wrapped in { v: T }, is checked as a whole
  • Turning it off with [T] extends [U], and turning it on deliberately with T extends unknown ? ... : never
  • Consequences: boolean distributes as true | false, never gives never (hence [T] extends [never] for IsNever), and Exclude / Extract depend on it
  • infer inside a distributive conditional runs per member (Unwrap<Promise<string> | number> is string | number); with the tuple wrapper it must match the whole union; infer X extends C (TypeScript 4.7) filters while extracting
  • Advanced uses: IsUnion, and contravariant infer candidates giving an intersection (UnionToIntersection)

Code / implementation expected: Yes β€” show ToArray both ways and an infer-based unwrap on a union.

  • conditional-types
  • infer

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

11 min read Β· 12 sections

Run the code

Edit the code and run it here. Each console line with an expected value becomes a test.

TypeScriptDistribution on and off: ToArray, IsNever and Exclude
TypeScriptinfer on unions: Unwrap, infer extends, IsUnion and UnionToIntersection

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 71 of 81 in TypeScript

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

How do TypeScript 5.0 Stage 3 decorators differ from legacy `experimentalDecorators`?

Continue