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 stringprzyinferzawęża to, co zostaje związane. Bez niegoFbyłobyunknown, 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.

