Przejdź do treści
webtype.orgwebtype.orgDwanaście zagadnień · 6/12

    ↑↓ 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ę.

    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