Challenge 1: Build a Query-String Type (Join) — Possible Solution ==================================================================== type Join = Words extends [infer First extends string, ...infer Rest extends string[]] ? Rest extends [] ? First : `${First}${Sep}${Join}` : ""; // --- Usage --- type A = Join<["a", "b", "c"], "-">; // "a-b-c" type B = Join<["path", "to", "file"], "/">; // "path/to/file" type C = Join<["only"], ",">; // "only" — single-element base case type D = Join<[], "-">; // "" — empty tuple base case // A practical use: building a typed route path from segments type BuildRoute = `/${Join}`; type UserRoute = BuildRoute<["users", "42", "posts"]>; // UserRoute = "/users/42/posts" // Runtime companion (types alone don't produce the string at runtime): function join(words: [...Words], sep: Sep): Join { return words.join(sep) as Join; } const joined = join(["a", "b", "c"] as ["a", "b", "c"], "-"); console.log(joined); // "a-b-c", typed as the literal "a-b-c" WHY THIS WORKS -------------- - Join destructures Words with [infer First extends string, ...infer Rest extends string[]] — the same [First, ...Rest] tuple pattern from Chapter 3's Head/Tail, but with an added `extends string` constraint on each captured piece so they can be safely used inside a template literal. - The base case is `Rest extends []` (exactly one element left): return First with no trailing separator, stopping the recursion from adding a dangling separator after the last word. - The recursive case wraps First, Sep, and a recursive Join inside a template literal — string concatenation happening entirely at the type level, one word at a time, until the base case is reached. - The empty-tuple case (Join<[], Sep>) falls through to the outer conditional's false branch since `[]` doesn't match the [infer First, ...infer Rest] pattern at all, producing "" — a sensible result for "join zero words."