Uczymy się utility types Extract, Exclude, uczymy się więcej o never oraz piszemy sami te utility types. Ciekawa lekcja, zaczynajmy.
Zanim zrozumiemy Extract i Exclude zobaczmy jak działa never w TS. Najpierw coś bardzo prostego, na pewno to znamy:
function foo() :never {
throw new Error("Error");
}
Ok, kolejna rzecz, która nie powinna nas dziwić:
let empArr = [];
type someT1 = typeof empArr;
//type someT1 = never[]
A teraz coś już naprawdę dziwnego, czyli unia typów razem z never:
type str123 = string | never;
//type str123 = string
Never jest ignorowane. Ok, zobaczmy sobie Extract i Exclude. Najpierw Exclude:
type T0 = Exclude<"a" | "b" | "c", "a">;
// type T0 = "b" | "c"
Jak widać zwróciło nam to po prawej, ale z wywalonymi rzeczami po lewej. Ok, Extract:
type T01 = Extract<"a" | "b" | "c", "a" | "f">;
//type T01 = "a"
Wyciągnęło nam te rzeczy po prawej, które występują po lewej. Brak f nie robi tu żadnego problemu, jak widać.
Dobra, ale jak to wszystko działa? Ano tak:
type T0 = Exclude<"a" | "b" | "c", "a">;
//type Exclude<T, U> = T extends U ? never : T
// type T0 = "b" | "c"
Exclude przyjmuje 2 typy. Sprawdza, czy T zawiera się w U, jeżeli tak, zwraca never, które jest ignorowane, jeżeli nie zwraca T. Ternary operator powinniśmy ogarniać.
Czyli de facto takie coś dostaliśmy:
type T0 = Exclude<"a" | "b" | "c", "a">;
//type Exclude<T, U> = T extends U ? never : T
// type T0 = never| "b" | "c"
Ale never jest ignorowane. A jak działa Extract?
type T01 = Extract<"a" | "b" | "c", "a" | "f">;
//type Extract<T, U> = T extends U ? T : never
//type T01 = "a"
Odwrotność Exclude. Sprawdza, czy T jest w U, jak jest, zwraca T, jak nie ma, zwraca never, które jest ignorowane.
Sami możemy sobie napisać MyExtract i MyExclude. W sumie wystarczy odkomentować i dodać My do nazwy… Najważniejsze, abyśmy rozumieli dlaczego tak się dzieje.
Ok, jeżeli nie ogarniamy conditional types i ternary operatora to tu jest przykład z docsów TSa:
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog extends Animal ? number : string;
//number
Proste. Spełnia warunek – number, nie spełnia – string. Tam po prostu mamy typ generyczny, never które jest ignorowane, unię, no może trochę to w głowie zamieszać, ale aż tak trudne chyba nie jest.
Po prostu musimy to sobie w głowie ułożyć. Do następnego razu!