Union Types i Intersection Types to dwa potężne narzędzia, które TypeScript oferuje do pracy z typami. Pozwalają na bardziej elastyczne definiowanie struktur danych, umożliwiając tworzenie typów złożonych, które mogą reprezentować różne możliwe wartości lub łączyć właściwości różnych typów.
Union Types (Typy łączone)
Typy łączone (ang. Union Types) umożliwiają definiowanie wartości, które mogą być jednym z kilku określonych typów. Są niezwykle przydatne, gdy chcemy zezwolić na różne możliwe wartości, ale z ograniczoną liczbą dopuszczalnych typów.
Składnia:
Typ łączony jest definiowany za pomocą pionowej kreski (|) pomiędzy typami, które mogą być użyte.
Przykład:
let id: number | string;
id = 123; // OK
id = "ABC"; // OK
// id = true; // Błąd: 'boolean' nie jest zgodny z typem 'number | string'
W powyższym przykładzie zmienna id może być zarówno liczbą (number), jak i tekstem (string), ale żaden inny typ (np. boolean) nie będzie akceptowany.
Typy łączone są przydatne w przypadkach, gdy zmienna może przyjąć różne, ale ograniczone wartości. Na przykład, ID użytkownika może być reprezentowane przez liczbę lub łańcuch znaków.
Przykład z funkcją:
function printId(id: number | string) {
if (typeof id === "string") {
console.log(`ID: ${id.toUpperCase()}`);
} else {
console.log(`ID: ${id}`);
}
}
printId(101); // Wypisze: ID: 101
printId("abc123"); // Wypisze: ID: ABC123
W powyższym przykładzie funkcja printId akceptuje parametr id, który może być zarówno liczbą, jak i łańcuchem znaków. Dzięki typeof, możemy odpowiednio reagować na różne typy i wykonywać różne operacje w zależności od tego, czy id jest liczbą czy tekstem.
Intersection Types (Typy przecięte)
Typy przecięte (ang. Intersection Types) pozwalają na tworzenie nowego typu, który łączy cechy wszystkich typów, z którymi zostaje połączony. Jest to używane, gdy chcemy stworzyć typ, który musi spełniać wszystkie właściwości kilku różnych typów jednocześnie.
Składnia:
Typ przecięty tworzymy za pomocą symbolu &, łącząc kilka typów.
Przykład:
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: number;
}
type EmployeePerson = Person & Employee;
let employee: EmployeePerson = {
name: "Jan",
age: 25,
employeeId: 12345
};
W tym przykładzie EmployeePerson jest typem przeciętym, który łączy właściwości zarówno interfejsu Person, jak i Employee. Obiekt employee musi posiadać wszystkie właściwości zarówno Person, jak i Employee, aby był poprawny.
Typy przecięte są przydatne w sytuacjach, gdy chcemy połączyć kilka niezależnych typów w jeden, reprezentujący obiekt o wszystkich wymaganych właściwościach.
Przykład z funkcją:
interface Developer {
language: string;
}
interface Manager {
teamSize: number;
}
type DevManager = Developer & Manager;
function describePerson(person: DevManager) {
console.log(`${person.language} developer, managing a team of ${person.teamSize}`);
}
describePerson({ language: "JavaScript", teamSize: 10 });
// Wypisze: JavaScript developer, managing a team of 10
W tym przykładzie DevManager to typ przecięty, który łączy właściwości Developer i Manager. Funkcja describePerson przyjmuje obiekt, który musi mieć zarówno pole language, jak i teamSize, dzięki czemu możemy z nim pracować jako z osobą o obu tych cechach.
Różnice między Union Types a Intersection Types
Union Types (Typy łączone) pozwalają na wybór jednej wartości spośród wielu typów. Wartość może być jednym z kilku typów, ale nie musi zawierać wszystkich właściwości naraz.
Przykład:
type A = string | number; // Może być stringiem LUB liczbą.
Intersection Types (Typy przecięte) wymagają połączenia cech z kilku typów. Obiekt musi zawierać wszystkie właściwości naraz, aby był zgodny z typem przeciętym.
Przykład:
type B = { name: string } & { age: number }; // Musi zawierać zarówno 'name', jak i 'age'.
Kiedy używać Union Types, a kiedy Intersection Types?
Typy łączone stosujemy, gdy chcemy, aby wartość mogła być jednym z kilku typów, ale nie naraz (np. ID może być liczbą LUB tekstem).
Typy przecięte stosujemy, gdy chcemy wymusić, aby obiekt zawierał wszystkie właściwości z kilku typów jednocześnie (np. Employee musi być jednocześnie Person i mieć dodatkową właściwość employeeId).
Podsumowanie
Typy łączone i przecięte w TypeScript to potężne narzędzia, które pozwalają na tworzenie bardziej elastycznych i złożonych typów. Union Types umożliwiają tworzenie zmiennych, które mogą przyjmować kilka różnych typów, co jest przydatne w sytuacjach, gdy mamy do czynienia z danymi o różnych formatach. Intersection Types pozwalają na łączenie cech z różnych typów, co pozwala na bardziej precyzyjne definiowanie struktur danych.
Dzięki wykorzystaniu tych narzędzi, możesz tworzyć kod, który jest bardziej elastyczny i lepiej dopasowany do rzeczywistych potrzeb aplikacji, zapewniając jednocześnie bezpieczeństwo typów i minimalizując błędy.