Przejdź do treści
webtype.orgwebtype.org#214 route-params · par 3

    ↑↓ ruch · ⏎ otwórz · esc zamknij

    Nr 214 · 22 lipca 2026 · Średnia

    Parametry trasy

    Zaimplementuj `ExtractParams<Path>`, aby każdy segment `:param` ścieżki stał się kluczem typu obiektowego o wartości `string`. Wynik musi być jednym płaskim obiektem — przecięcie nie przejdzie.

    01

    Spróbuj rozwiązać samodzielnie

    Par 3

    Zagadka

    route-params.ts
    type Prettify<T> = { [K in keyof T]: T[K] } & {}
    Podejście 1 z 3Jeszcze nie sprawdzone

    Zastąp ??? — rozwiązanie sprawdzamy przypadkami poniżej. Tab wcina; naciśnij Escape, a potem Tab, by wyjść fokusem.

    Testy

    4
    • ExtractParams<'/about'>
      {}
    • ExtractParams<'/users/:id'>
      { id: string }
    • ExtractParams<'/users/:id/posts/:postId'>
      { id: string; postId: string }
    • ExtractParams<'/:org/:repo/issues/:number'>
      { org: string; repo: string; number: string }

    Jak oceniamy test Dokładna równość typów, nie przypisywalność — przecięcie to nie to samo co spłaszczony obiekt.

    Jak poszło innym

    Tę zagadkę rozwiązało jak dotąd mniej niż 5 osób. Rozkład pojawi się, gdy próbka będzie na tyle duża, by coś znaczyć.

    Gra na krótkim dystansie

    Najmniej znaków

    Nie ma jeszcze publicznych wyników.

    Archiwum
    02

    Rozwiązanie z komentarzem

    Opublikowano 23 lipca 2026

    Rozwiązanie

    type ExtractParams<Path extends string> = Prettify<
      Path extends `${string}:${infer Param}/${infer Rest}`
        ? { [K in Param]: string } & ExtractParams<`/${Rest}`>
        : Path extends `${string}:${infer Param}`
          ? { [K in Param]: string }
          : {}
    >

    Najczęstsza błędna odpowiedź

    type ExtractParams<Path extends string> =
      Path extends `${string}:${infer Param}/${infer Rest}`
        ? { [K in Param]: string } & ExtractParams<`/${Rest}`>
        : Path extends `${string}:${infer Param}`
          ? { [K in Param]: string }
          : {}

    Wszystko tu jest poprawne poza kształtem wyniku. Powstaje `{ id: string } & { postId: string }`, co da się przypisać do `{ id: string; postId: string }`, ale to nie ten sam typ — a testy sprawdzają dokładną równość. Owinięcie całości w `Prettify` spłaszcza przecięcie do jednego obiektu.

    Linia po linii

    1. `${string}:${infer Param}/${infer Rest}`

      Wiodące `${string}` pochłania wszystko przed dwukropkiem, więc wzorzec nie przejmuje się tym, że ścieżka zaczyna się od `/users`. `Param` wiąże się aż do następnego ukośnika; `Rest` bierze całą resztę.

    2. ExtractParams<`/${Rest}`>

      Ukośnik jest dokładany z powrotem przed rekurencją. Bez niego końcowy segment w rodzaju `posts/:postId` wciąż pasowałby do pierwszego wzorca i rekurencja nie kończyłaby się czysto.

    3. Path extends `${string}:${infer Param}`

      Drugi wzorzec nie ma końcowego ukośnika, więc pasuje tylko wtedy, gdy parametr jest ostatnim elementem łańcucha. To przypadek bazowy zatrzymujący rekurencję.

    4. Prettify<...>

      Mapuje raz jeszcze po zebranych kluczach, tworząc świeży typ obiektowy. Końcówka `& {}` w `Prettify` zmusza TypeScript do faktycznego wyliczenia typu mapowanego zamiast trzymania go leniwie.

    Do zapamiętania

    Wzorce literałów szablonowych dopasowują się zachłannie od lewej. Gdy zbierasz typy obiektowe przez rekurencję, dostajesz przecięcie, a testy dokładnej równości je odrzucą — spłaszcz je przed zwróceniem.

    Wykorzystuje