Przejdź do treści
webtype.orgwebtype.org

    ↑↓ ruch · ⏎ otwórz · esc zamknij

    Zagadnienie 6 z 12

    Typy warunkowe

    Typ warunkowy to if na poziomie typów. Zadaje zawsze to samo pytanie: czy lewa strona jest przypisywalna do prawej? Nie „czy są równe”, nie „czy to instancja” — przypisywalna, i to w jedną stronę.

    Prześledź typSprawdzone kompilatorem
    WyrażenieIsText<"hello">
    Rozwija się dotrue
    WyrażenieIsText<42>
    Rozwija się dofalse

    extends pyta o przypisywalność. Literał łańcucha trafia do gałęzi true, a liczba do false.

    Definicja typu
    type IsText<T> = T extends string ? true : false

    Przypisywalność, nie równość

    type A = 'hello' extends string ? true : false   // true
    type B = string extends 'hello' ? true : false   // false
    type C = never extends string ? true : false     // true — never fits anywhere
    type D = { a: 1; b: 2 } extends { a: 1 } ? true : false  // true

    Typ węższy jest przypisywalny do szerszego, więc test ma kierunek. Obiekt z dodatkowymi właściwościami jest przypisywalny do obiektu z mniejszą liczbą — dlatego extends nie sprawdzi, czy dwa typy obiektowe mają ten sam kształt.

    Gdy naprawdę potrzebujesz „tego samego typu”, potrzebujesz pomocnika Equal, na którym oparty jest każdy test na tej stronie — dwa odroczone warunki porównywane co do tożsamości, co jest surowsze niż przypisywalność w obie strony.

    Gałęzie sprawdzane są po kolei

    type Describe<T> = T extends (...args: never[]) => unknown
      ? 'function'
      : T extends unknown[]
        ? 'array'
        : T extends object
          ? 'object'
          : 'primitive'

    Węższe przypadki muszą iść pierwsze. Funkcje i tablice są obiektami, więc wczesne sprawdzenie extends object je pochłonie — to klasyczna przyczyna DeepReadonly, które po cichu niszczy każdą napotkaną funkcję.

    Najczęstsza błędna odpowiedź

    // Intent: is T exactly string?
    type IsString<T> = T extends string ? true : false
    
    IsString<'hello'>  // true — but 'hello' is not string, it is narrower
    IsString<any>      // boolean — any matches both branches at once

    extends odpowiada na „mieści się w”, więc każdy literał łańcuchowy przechodzi test na string. A any jest przypisywalne do wszystkiego, więc warunek z any zwraca unię obu gałęzi — wynik, o który autor prawie nigdy nie prosił.

    Ćwiczenie

    Odpowiedz true, gdy T jest string, a false w przeciwnym razie.

    Spróbuj

    2
    • IsString<'a'>—
      → true
    • IsString<number>—
      → false

    Do zapamiętania

    Warunki pytają o przypisywalność i sprawdzają gałęzie po kolei. Najpierw węższe, a po Equal sięgaj, gdy tylko potrzebujesz prawdziwej tożsamości.

    Ćwiczone w