Annotated solution
Published August 28, 2026The solution
type Repeat< S extends string, N extends number, Acc extends unknown[] = [], > = Acc['length'] extends N ? '' : `${S}${Repeat<S, N, [...Acc, unknown]>}`
The common wrong answer
type Repeat< S extends string, N extends number, Acc extends unknown[] = [], > = Acc['length'] extends N ? S : `${S}${Repeat<S, N, [...Acc, unknown]>}`
The base case emits one copy too many. Returning `S` when the counter is full means the terminating step also contributes, so `Repeat<"ab", 3>` produces four copies — and `Repeat<"x", 0>` returns `"x"` when it should return nothing at all.
Line by line
Acc['length'] extends N ? ''The base case must be the *identity* of the operation being built. For concatenation that is the empty string, exactly as `[]` is the base case when building a tuple and `0` would be when adding numbers.
[...Acc, unknown]The accumulator holds `unknown` because its contents are irrelevant — only its length is being read. It is a tally, not a collection.
Takeaway
Whenever a type-level loop is off by one, look at what the base case returns rather than at the recursive step. The terminating branch should contribute the neutral element, not another copy of the payload.

