Rozwiązanie z komentarzem
Opublikowano 2 sierpnia 2026Rozwiązanie
type Join<T extends readonly string[], D extends string> = T extends readonly [infer F extends string, ...infer R extends string[]] ? R extends readonly [] ? F : `${F}${D}${Join<R, D>}` : ''
Najczęstsza błędna odpowiedź
type Join<T extends readonly string[], D extends string> = T extends readonly [infer F extends string, ...infer R extends string[]] ? `${F}${D}${Join<R, D>}` : ''
Każdy poziom dokłada separator, łącznie z ostatnim, więc `["a","b","c"]` daje `"a-b-c-"`. Łączenie to nie „wstaw separator po każdym elemencie”, tylko „wstaw separator *pomiędzy* elementy” — a różnica ujawnia się dopiero na końcu.
Linia po linii
infer F extends stringOgraniczenie `extends string` przy `infer` zawęża to, co zostaje związane. Bez niego `F` byłoby `unknown`, którego nie da się wstawić do typu literału szablonowego.
R extends readonly [] ? FStrażnik, który czyni z tego złączenie, a nie dopisek. Gdy nic nie następuje, element trafia na wyjście sam i rekurencja kończy się bez dokładania separatora.
Do zapamiętania
Rekurencyjne budowanie łańcuchów prawie zawsze potrzebuje osobnego przypadku bazowego dla ostatniego elementu. Jeśli na końcu wyniku zostaje samotny separator, tego przypadku brakuje.