Skip to content
webtype.orgwebtype.org#229 flatten-tuple · par 4

    ↑↓ move · ⏎ open · esc close

    No. 229 · August 6, 2026 · Hard

    Flatten

    Implement `Flatten<T>` so it flattens a nested tuple completely, to any depth.

    01

    Try the puzzle yourself

    Par 4

    Puzzle

    flatten-tuple.ts
    Stroke 1 of 4Not run yet

    Replace ??? — your solution is checked against the cases below. Tab indents; press Escape then Tab to move focus out.

    Checks

    4
    • Flatten<[1, [2, 3], 4]>
      [1, 2, 3, 4]
    • Flatten<[]>
      []
    • Flatten<[[[1]]]>
      [1]
    • Flatten<[1, [2, [3, [4]]]]>
      [1, 2, 3, 4]

    How a check is judged Exact type equality, not assignability — an intersection is not the same as the flattened object.

    How everyone did

    Fewer than 5 people have solved this one so far. The distribution appears once there is enough of a sample to mean anything.

    Short game

    Fewest characters

    No public scores yet.

    Archive
    02

    Annotated solution

    Published August 7, 2026

    The solution

    type Flatten<T extends readonly unknown[]> =
      T extends readonly [infer H, ...infer R]
        ? H extends readonly unknown[]
          ? [...Flatten<H>, ...Flatten<R>]
          : [H, ...Flatten<R>]
        : []

    The common wrong answer

    type Flatten<T extends readonly unknown[]> =
      T extends readonly [infer H, ...infer R]
        ? H extends readonly unknown[]
          ? [...H, ...Flatten<R>]
          : [H, ...Flatten<R>]
        : []

    Spreading `H` directly unwraps exactly one layer, so `[[[1]]]` flattens to `[[1]]` and stops. The head must be flattened recursively too — it is not merely a container to open, it is a whole nested structure.

    Line by line

    1. H extends readonly unknown[]

      The branch that decides whether this element needs opening. `readonly unknown[]` matches both mutable and readonly tuples, so neither is accidentally treated as a scalar.

    2. [...Flatten<H>, ...Flatten<R>]

      Two recursive calls, one going down into the nesting and one going along the tuple. That pair is what makes the flattening total rather than single-level.

    Takeaway

    Recursing in one direction walks a list; recursing in two walks a tree. Most "it only went one level deep" bugs are a missing second recursive call.

    Uses