Question presented to candidate:
"Using infer, build me a deep version of Awaited, a ReturnType that sees through curried functions, and a general Unwrap that peels promises, arrays and functions. Then tell me where these break."
What a strong answer should cover:
- The recipe: a conditional type whose true branch calls itself on the inferred part (
T extends PromiseLike<infer V> ? DeepAwaited<V> : T), with the false branch as the base case - Ordering several
inferchecks in one chain (promise, then array, then function) and choosing what non-matching types return - Distribution: a naked
Tunwraps each union member separately;[T] extends [...]tests the union as a whole - Practical use: mapping an API client to its resolved data with
Awaited<ReturnType<...>>, and typing arguments withinfer P - Limits: deep unwraps are greedy, special inputs (
any,never,unknown), and the instantiation depth limit (error TS2589); tail-recursive conditional types (TypeScript 4.5) go much deeper
Clarifying questions expected:
- Should
Unwrapstop at arrays and functions, or only peel promises? - Should a union be unwrapped member by member, or treated as one type?
Code / implementation expected: Yes β write the recursive utilities and show them on nested input.