W tym wpisie omówię keyof, typeof, mapped types, conditional types i dowiesz się, jak używać ich w codziennej pracy.
Wprowadzenie do Typów w TypeScript
TypeScript (TS) to nadzbiór JavaScriptu, który dodaje statyczne typowanie do języka.
Dzięki temu możesz typować swoje zmienne, funkcje i obiekty, co pomaga wykrywać błędy już na etapie kompilacji.
Ale TypeScript to nie tylko podstawowe typy jak stringi czy number. Pozwala też na zaawansowane techniki typowania, takie jak keyof, typeof, mapped types i conditional types.
Zrozumienie Keyof w TypeScript
Co to jest Keyof?
Słowo kluczowe keyof to operator w TypeScripcie, który zwraca unię łańcuchów reprezentujących nazwy wszystkich kluczy danego typu obiektowego.
Jak Używać Keyof?
Załóżmy, że masz interfejs:
interface User {
id: number;
name: string;
email: string;
}
Kiedy użyjesz keyof User
, otrzymasz typ równoważny 'id' | 'name' | 'email'
.
Przykład z Keyof
type UserKeys = keyof User; // 'id' | 'name' | 'email'
let key: UserKeys;
key = "name"; // OK
key = "address"; // Błąd: Type '"address"' is not assignable to type 'UserKeys'
Dzięki keyof możesz tworzyć bardziej zaawansowane typy, które gwarantują, że używasz tylko dostępnych kluczy obiektu.
Co to jest Typeof w JavaScript?
W JavaScripcie mamy operator typeof
, który zwraca typ zmiennej w postaci łańcucha znaków, np. 'string'
, 'number'
.
W TypeScripcie operator typeof może być użyty w kontekście typowania, aby odczytać typ danej zmiennej lub obiektu.
Jak Używać Typeof w TypeScript?
Jeśli masz zmienną:
let user = {
id: 1,
name: "Alice",
email: "alice@example.com",
};
Możesz utworzyć typ bazujący na typie tej zmiennej:
type UserType = typeof user;
Teraz UserType
ma dokładnie ten sam typ, co user
.
Przykład z Typeof
function getUser(): UserType {
return {
id: 2,
name: "Bob",
email: "bob@example.com",
};
}
Typeof pozwala przypisać typ istniejącej zmiennej do nowego typu.
Co to są Mapped Types w TypeScript?
Mapped types to typy, które pozwalają na mapowanie jednego typu na inny, przekształcając jego właściwości.
Użycie Mapped Types: Partial, Required, Readonly, Pick, Omit
TypeScript dostarcza kilka wbudowanych utility types, które są mapped types:
Partial<T>
: Ustawia wszystkie właściwości typuT
jako opcjonalne.Required<T>
: Ustawia wszystkie właściwości typuT
jako wymagane.Readonly<T>
: Ustawia wszystkie właściwości typuT
jako tylko do odczytu.Pick<T, K>
: Tworzy typ z podzbioru właściwościK
z typuT
.Omit<T, K>
: Tworzy typ z właściwości typuT
bez właściwościK
.
Przykładowy Mapped Type
Partial
type PartialUser = Partial<User>;
// Wszystkie właściwości są opcjonalne
let user1: PartialUser = { name: "Charlie" };
Required
type RequiredUser = Required<User>;
// Wszystkie właściwości są wymagane
let user2: RequiredUser = {
id: 3,
name: "Dana",
email: "dana@example.com",
};
Pick
type UserNameAndEmail = Pick<User, "name" | "email">;
// Typ z tylko 'name' i 'email'
let user3: UserNameAndEmail = {
name: "Eve",
email: "eve@example.com",
};
Omit
type UserWithoutEmail = Omit<User, "email">;
// Typ z wszystkimi właściwościami poza 'email'
let user4: UserWithoutEmail = {
id: 4,
name: "Frank",
};
Tworzenie Własnych Mapped Types
Możesz też tworzyć własne mapped types:
type MyMappedType<T> = {
[P in keyof T]: string;
};
// Wszystkie właściwości typu T będą typu string
type StringifiedUser = MyMappedType<User>;
let user5: StringifiedUser = {
id: "5",
name: "Grace",
email: "grace@example.com",
};
Zaawansowane Typowanie z Conditional Types
Zrozumienie Conditional Types
Conditional types pozwalają na tworzenie typów, które zależą od pewnych warunków.
Składnia jest podobna do operatora trójargumentowego w JavaScript:
T extends U ? X : Y
Jeśli T
jest podtypem U
, to wynikiem jest X
, w przeciwnym razie Y
.
Przykład z Conditional Types
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
Zastosowania Conditional Types
Conditional types są bardzo przydatne w kontekście tworzenia typów generycznych, które mogą się zmieniać w zależności od przekazanych parametrów.
Łączenie Keyof, Typeof i Mapped Types
Tworzenie Typu na Podstawie Kluczy Obiektu
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let user6 = { id: 6, name: "Hank", email: "hank@example.com" };
let userName = getProperty(user6, "name"); // Typ string
Tutaj użyliśmy keyof do ograniczenia klucza K
do istniejących kluczy obiektu T
.
Użycie Typeof z Keyof
const COLORS = {
red: "#FF0000",
green: "#00FF00",
blue: "#0000FF",
};
type ColorKeys = keyof typeof COLORS; // 'red' | 'green' | 'blue'
Typeof pozwala nam utworzyć typ na podstawie COLORS
, a keyof wyciąga klucze tego typu.
Podsumowanie
Poznanie keyof i typeof w TypeScript otwiera drzwi do bardziej zaawansowanych technik typowania.
Mapped types, takie jak Partial, Required, Pick, czy Omit, ułatwiają manipulowanie typami i tworzenie bardziej elastycznego kodu.
Conditional types dodają kolejny poziom dynamiki, pozwalając na typowanie zależne od warunków.
Mam nadzieję, że ten artykuł pomógł Ci zrozumieć te potężne narzędzia w TypeScript. Zachęcam do eksperymentowania i programowania własnych rozwiązań. Jeśli masz pytania lub chcesz podzielić się swoimi doświadczeniami, zostaw komentarz!