Rozwiązanie z komentarzem
Opublikowano 6 września 2026Rozwiązanie
type SnakeCase<S extends string> = S extends `${infer H}${infer R}` ? H extends Uppercase<H> ? H extends Lowercase<H> ? `${H}${SnakeCase<R>}` : `_${Lowercase<H>}${SnakeCase<R>}` : `${H}${SnakeCase<R>}` : S
Najczęstsza błędna odpowiedź
type SnakeCase<S extends string> = S extends `${infer H}${infer R}` ? H extends Uppercase<H> ? `_${Lowercase<H>}${SnakeCase<R>}` : `${H}${SnakeCase<R>}` : S
"1" extends Uppercase<"1"> jest prawdą, bo Uppercase zostawia wszystko, co nie jest małą literą, dokładnie takim, jakie zastało. Każda cyfra, spacja i symbol traktowane są więc jak wielka litera i dostają własne podkreślenie: "a1B" wychodzi jako "a_1_b". Wielkość znaku to nie jeden test, lecz dwa — równy swojej wersji wielkiej *i* różny od swojej małej.
Linia po linii
`${infer H}${infer R}`Dwa symbole zastępcze bez niczego pomiędzy odcinają dokładnie jeden znak. To typowy odpowiednik przechodzenia po tekście indeks po indeksie.
H extends Lowercase<H> ? ... : ...Drugi test wyklucza znaki niebędące literami. Cyfra jest równa i swojej wersji wielkiej, i małej, więc trafia do gałęzi, która przepuszcza ją bez zmian.
: SPusty ciąg nie pasuje do żadnego jednoznakowego wzorca, więc spada do przypadku bazowego i zwraca sam siebie — co zarazem zatrzymuje rekurencję.
Do zapamiętania
Uppercase i Lowercase są funkcjami totalnymi: nigdy nie zawodzą, po prostu nic nie robią znakom bez wielkości. Każdy test oparty tylko na jednej z nich po cichu źle sklasyfikuje każdą napotkaną cyfrę i symbol.

