TypeScript dostarcza wiele wbudowanych typów użytkowych (Utility Types), które pomagają w codziennej pracy z typami i obiektami. Są to typy, które pozwalają na modyfikowanie lub wyciąganie typów na różne sposoby, co zwiększa elastyczność i ułatwia pracę z bardziej złożonymi strukturami danych.
W tej sekcji omówimy najczęściej używane typy użytkowe, takie jak Partial, Readonly, oraz Pick.
Typ Partial
Partial<T> jest typem użytkowym, który pozwala na tworzenie wersji typu T, w której wszystkie właściwości są opcjonalne. Jest to przydatne w sytuacjach, gdy nie chcemy, aby wszystkie pola w obiekcie były obowiązkowe, np. przy aktualizacji tylko niektórych właściwości w obiekcie.
Przykład:
Załóżmy, że mamy interfejs User, który określa strukturę obiektu użytkownika:
interface User {
name: string;
age: number;
email: string;
}
Domyślnie wszystkie właściwości są wymagane. Jeśli jednak chcemy stworzyć funkcję, która aktualizuje tylko niektóre właściwości użytkownika, możemy użyć Partial:
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
let user: User = { name: "Jan", age: 30, email: "jan@example.com" };
let updatedUser = updateUser(user, { email: "jan.nowy@example.com" });
console.log(updatedUser);
// Zwraca: { name: "Jan", age: 30, email: "jan.nowy@example.com" }
W tym przykładzie, Partial<User> pozwala nam na przekazanie obiektu z opcjonalnymi właściwościami, takimi jak email, bez konieczności podawania pozostałych pól.
Typ Readonly
Typ Readonly przekształca wszystkie właściwości typu T w tylko do odczytu (readonly). Oznacza to, że raz przypisana wartość nie może być zmieniona. Przydaje się to w sytuacjach, gdy chcemy zapewnić niezmienność obiektów i chronić je przed przypadkowymi modyfikacjami.
Tutaj Readonly<Car> sprawia, że obiekt myCar staje się niezmienny – żadna z jego właściwości nie może być nadpisana.
Typ Pick
Pick<T, K> pozwala na wybranie kilku właściwości z istniejącego typu i stworzenie nowego typu, który zawiera tylko te właściwości. Jest to przydatne, gdy chcemy stworzyć nowy typ z podzbiorem właściwości innego typu.
W tym przykładzie Pick<Employee, "id" | "name"> tworzy nowy typ EmployeeOverview, który zawiera tylko właściwości id i name z typu Employee. Dzięki temu możemy pracować z podzbiorem właściwości, co często bywa użyteczne w dużych projektach.
Typ Omit
Typ Omit<T, K> działa odwrotnie do Pick – pozwala na usunięcie wybranych właściwości z istniejącego typu. Jest to przydatne, gdy chcemy pozbyć się pewnych właściwości, których nie potrzebujemy w danym kontekście.
Przykład:
type EmployeeWithoutSalary = Omit<Employee, "salary">;
let employee: EmployeeWithoutSalary = {
id: 1,
name: "Jan Nowak",
position: "Developer",
};
W tym przypadku Omit<Employee, "salary"> tworzy nowy typ EmployeeWithoutSalary, który zawiera wszystkie właściwości z wyjątkiem salary.
Typ Record
Typ Record<K, T> pozwala na stworzenie obiektu, w którym klucze są typu K, a wartości są typu T. Jest to przydatne, gdy chcemy stworzyć obiekt, który będzie przechowywał wartości o jednolitym typie, a klucze będą reprezentować określony typ.
Tutaj Record<ProductCategories, number> tworzy obiekt, w którym klucze to nazwy kategorii produktów ("electronics", "clothing", "groceries"), a wartości to liczby, reprezentujące ilość produktów w każdej kategorii.
Typ Required
Typ Required<T> zmienia wszystkie właściwości obiektu na obowiązkowe (czyli usuwa ewentualne oznaczenie opcjonalności ?). Jest to przydatne w sytuacjach, gdzie chcemy mieć pewność, że wszystkie pola zostaną uzupełnione.
Przykład:
interface User {
name?: string;
age?: number;
}
let requiredUser: Required<User> = {
name: "Anna",
age: 25,
};
// Teraz zarówno 'name', jak i 'age' są wymagane
Required<User> przekształca wszystkie opcjonalne właściwości w obowiązkowe, co oznacza, że musimy teraz podać zarówno name, jak i age.
Typ NonNullable
Typ NonNullable<T> usuwa z typu T wartości null oraz undefined. Jest to przydatne, gdy chcemy upewnić się, że dana wartość nie będzie pusta.
Przykład:
type Name = string | null | undefined;
let validName: NonNullable<Name> = "Jan";
// validName nie może być null ani undefined
W tym przykładzie NonNullable<Name> tworzy typ, który pozwala tylko na wartości typu string, eliminując null i undefined.
Podsumowanie
Typy użytkowe w TypeScript, takie jak Partial, Readonly, Pick, czy Omit, są niezwykle przydatne, ponieważ pozwalają na tworzenie bardziej elastycznego i zwięzłego kodu, który jest łatwiejszy do utrzymania i mniej podatny na błędy. Te narzędzia dają możliwość modyfikowania istniejących typów w różnych kierunkach, co ułatwia pracę z bardziej złożonymi strukturami danych. Dzięki nim możesz w łatwy sposób definiować typy, które są dostosowane do potrzeb twojego projektu, co czyni kod bardziej skalowalnym i zrozumiałym.