Hint
The infer keyword captures the type matched in the extends pattern. T extends Array<infer E> says "if T is an array, name the element type E". Then you use E in the true branch. This is how Awaited, ReturnType, and Parameters are built.
// Simulate: type Unwrap<T> = T extends Array<infer E> ? E : T
// and: type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T
function unwrapArray(arr) {
if (Array.isArray(arr)) return arr[0];
return arr;
}
function unwrapPromiseSync(p) {
// Synchronously simulate what the type resolves to
if (p && typeof p.then === 'function') {
return 'Promise<' + typeof p._value + '>';
}
return typeof p;
}
// Unwrap<number[]> => number (element type)
// Unwrap<string[]> => string
// Unwrap<string> => string (not an array, identity)
console.log(typeof unwrapArray([1, 2, 3])); // number (element)
console.log(typeof unwrapArray(['a', 'b'])); // string (element)
console.log(typeof unwrapArray('hello')); // string (not array — identity)
console.log(typeof unwrapArray([true, false])); // booleannumber string string boolean
Explanation: unwrapArray returns the first element for arrays (the inferred element type E) and the value itself for non-arrays. This mirrors Unwrap
Key Insight: The infer keyword captures the type matched in the extends pattern. T extends Array