Challenge 1: Write a Recursive Flatten Type — Possible Solution ==================================================================== type FlattenArray = T extends (infer E)[] ? FlattenArray : T; // --- Usage --- type A = FlattenArray; // number type B = FlattenArray; // string type C = FlattenArray; // boolean (base case — never was an array) type D = FlattenArray; // number — works for any depth of nesting // Step-by-step for FlattenArray: // // FlattenArray // -> extends (infer E)[]? yes, E = number[][] // -> recurse: FlattenArray // -> extends (infer E)[]? yes, E = number[] // -> recurse: FlattenArray // -> extends (infer E)[]? yes, E = number // -> recurse: FlattenArray // -> extends (infer E)[]? NO — base case, return number WHY THIS WORKS -------------- - Each recursive call strips exactly one array layer via `infer E`, then immediately recurses on E — the same self-recursive conditional type pattern as Chapter 1's DeepAwaited, just unwrapping array brackets instead of Promise wrappers. - The base case is implicit: once T is no longer an array type, the `extends (infer E)[]` check fails and the false branch (`: T`) returns the current T unchanged, terminating the recursion. - This works for any depth of nesting because the recursion doesn't hard-code a number of levels — it keeps unwrapping until there's nothing left to unwrap, exactly like DeepAwaited kept unwrapping Promises.