Kurs JavaScript i TypeScript · Moduł 6: Podstawy TypeScript

Typy union i intersection

9 min czytania
W tej lekcji4

Witaj w zaawansowanym laboratorium typów TypeScript w Parku Jurajskim! Dr. Henry Wu jest dziś szczególnie podekscytowany, ponieważ będziemy omawiać dwa potężne mechanizmy TypeScript, które można porównać do jego najbardziej ambitnych projektów inżynierii genetycznej: typy union (unii) i intersection (przecięcia).

Union Types - czyli "albo to, albo to"

Typ union (unii) pozwala zmiennej przyjmować wartości jednego z kilku różnych typów. To trochę jak wybieg hybrydowy w parku, który może pomieścić różne gatunki dinozaurów, ale tylko jeden rodzaj na raz.

Podstawowa składnia typów union

Typ union tworzymy za pomocą operatora | (pionowa kreska):

1// Zmienna może być typu string LUB number
2let identyfikatorDinozaura: string | number;
3
4identyfikatorDinozaura = "TREX-01"; // Ok, string jest dozwolony
5identyfikatorDinozaura = 12345;     // Ok, number jest dozwolony
6// identyfikatorDinozaura = true;   // Błąd! boolean nie jest częścią unii string | number

Praktyczne zastosowania typów union

Typy union są niezwykle przydatne w wielu praktycznych scenariuszach w Parku Jurajskim:

1. Obsługa różnych formatów identyfikatorów

1// Funkcja, która może przyjąć różne typy identyfikatorów
2function znajdźDinozaura(id: string | number): void {
3  // Musimy sprawdzić typ, zanim wykonamy operacje specyficzne dla danego typu
4  if (typeof id === "string") {
5    console.log(`Szukam dinozaura o kodzie: ${id.toUpperCase()}`);
6  } else {
7    console.log(`Szukam dinozaura o numerze: ${id.toFixed(0)}`);
8  }
9}
10
11znajdźDinozaura("RAPTOR-BLUE"); // "Szukam dinozaura o kodzie: RAPTOR-BLUE"
12znajdźDinozaura(42);            // "Szukam dinozaura o numerze: 42"

2. Funkcje zwracające różne typy

1// Funkcja, która może zwrócić dinozaura lub komunikat o błędzie
2function pobierzDaneDinozaura(id: string):
3  { nazwa: string; gatunek: string; wiek: number } | string {
4
5  // Symulacja bazy danych
6  const bazaDanych = new Map([
7    ["TRex1", { nazwa: "Rex", gatunek: "Tyrannosaurus", wiek: 7 }],
8    ["Rap1", { nazwa: "Blue", gatunek: "Velociraptor", wiek: 4 }]
9  ]);
10
11  const dinozaur = bazaDanych.get(id);
12
13  if (dinozaur) {
14    return dinozaur; // Zwraca obiekt dinozaura
15  } else {
16    return `Nie znaleziono dinozaura o ID: ${id}`; // Zwraca komunikat błędu
17  }
18}
19
20const wynik = pobierzDaneDinozaura("TRex1");
21// Musimy sprawdzić typ zwróconej wartości
22if (typeof wynik === "string") {
23  console.log(`Błąd: ${wynik}`);
24} else {
25  console.log(`Znaleziono: ${wynik.nazwa}, gatunek: ${wynik.gatunek}`);
26}

3. Obsługa opcjonalnych parametrów

1// Funkcja tworząca raport, która może przyjąć różne parametry filtrowania
2function generujRaportDinozaurów(
3  filtr?: { gatunek?: string; minWiek?: number; drapieżniki?: boolean }
4): string {
5  let raport = "Raport dinozaurów:\n";
6
7  if (filtr) {
8    raport += "Filtry:";
9    if (filtr.gatunek) raport += ` Gatunek=${filtr.gatunek}`;
10    if (filtr.minWiek) raport += ` MinWiek=${filtr.minWiek}`;
11    if (filtr.drapieżniki !== undefined) raport += ` TylkoDrapieżniki=${filtr.drapieżniki}`;
12  } else {
13    raport += "Brak filtrów - pokazuję wszystkie dinozaury";
14  }
15
16  return raport;
17}
18
19console.log(generujRaportDinozaurów()); // Bez filtrów
20console.log(generujRaportDinozaurów({ gatunek: "Velociraptor" })); // Z filtrem gatunku
21console.log(generujRaportDinozaurów({ minWiek: 5, drapieżniki: true })); // Z wieloma filtrami

Discriminated Unions (Unie dyskryminacyjne)

Unie dyskryminacyjne to zaawansowana technika używania typów union z "właściwością dyskryminującą", która pozwala TypeScriptowi rozpoznać, z którym typem mamy do czynienia. To jak system identyfikacji dinozaurów w parku, który pozwala natychmiast rozpoznać, czy mamy do czynienia z roślinożercą czy drapieżnikiem.

1// Definiowanie interfejsów z właściwością dyskryminującą "typ"
2interface Roślinożerca {
3  typ: "roślinożerca";
4  dieta: string[];
5  poziomAgresji: number; // 1-10
6}
7
8interface Drapieżnik {
9  typ: "drapieżnik";
10  ofiary: string[];
11  siłaUgryzienia: number; // w PSI
12}
13
14// Typ będący unią dwóch interfejsów
15type Dinozaur = Roślinożerca | Drapieżnik;
16
17// Funkcja korzystająca z unii dyskryminacyjnej
18function zarządzajDinozaurem(dino: Dinozaur): void {
19  // Sprawdzamy właściwość dyskryminującą
20  switch (dino.typ) {
21    case "roślinożerca":
22      // TypeScript wie, że tutaj dino jest typu Roślinożerca
23      console.log(`Przygotuj paszę: ${dino.dieta.join(", ")}`);
24      if (dino.poziomAgresji > 7) {
25        console.log("Uwaga: Roślinożerca z wysokim poziomem agresji!");
26      }
27      break;
28    case "drapieżnik":
29      // TypeScript wie, że tutaj dino jest typu Drapieżnik
30      console.log(`Przygotuj mięso dla: ${dino.ofiary.join(", ")}`);
31      if (dino.siłaUgryzienia > 10000) {
32        console.log("Uwaga: Bardzo niebezpieczny drapieżnik!");
33      }
34      break;
35  }
36}
37
38// Przykłady użycia
39const triceratops: Roślinożerca = {
40  typ: "roślinożerca",
41  dieta: ["paprocie", "cykady", "iglaste"],
42  poziomAgresji: 6
43};
44
45const tRex: Drapieżnik = {
46  typ: "drapieżnik",
47  ofiary: ["triceratops", "edmontosaurus", "pachycephalosaurus"],
48  siłaUgryzienia: 12800
49};
50
51zarządzajDinozaurem(triceratops);
52zarządzajDinozaurem(tRex);

Intersection Types - czyli "to i to"

Typ intersection (przecięcia) pozwala na połączenie wielu typów w jeden, bardziej złożony typ. To jak eksperymenty Dr. Wu z łączeniem DNA różnych dinozaurów, by stworzyć zupełnie nowe gatunki o cechach wszystkich "składników".

Podstawowa składnia typów intersection

Typ intersection tworzymy za pomocą operatora &:

1// Definiowanie interfejsów podstawowych cech
2interface PodstawowyDinozaur {
3  id: number;
4  nazwa: string;
5  gatunek: string;
6  wiek: number;
7}
8
9interface CechyFizyczne {
10  wysokość: number; // w metrach
11  długość: number; // w metrach
12  waga: number;   // w kilogramach
13}
14
15interface CechyBehawioralne {
16  poziomAgresji: number; // 1-10
17  terytorialny: boolean;
18  społeczny: boolean;
19}
20
21// Tworzenie typu będącego przecięciem trzech interfejsów
22type PełnyProfilDinozaura = PodstawowyDinozaur & CechyFizyczne & CechyBehawioralne;
23
24// Teraz obiekt musi implementować wszystkie właściwości ze wszystkich trzech interfejsów
25const velociraptor: PełnyProfilDinozaura = {
26  // Z PodstawowyDinozaur
27  id: 101,
28  nazwa: "Blue",
29  gatunek: "Velociraptor",
30  wiek: 4,
31
32  // Z CechyFizyczne
33  wysokość: 0.5,
34  długość: 2,
35  waga: 15,
36
37  // Z CechyBehawioralne
38  poziomAgresji: 8,
39  terytorialny: true,
40  społeczny: true
41};

Praktyczne zastosowania typów intersection

Typy intersection są szczególnie przydatne w budowaniu złożonych systemów w Parku Jurajskim:

1. Kompozycja zachowań

1// Definiowanie różnych umiejętności
2interface Pływający {
3  prędkośćPływania: number; // km/h
4  maksGłębokość: number;    // metry
5  wytrzymałośćPodWodą: number; // minuty
6}
7
8interface Latający {
9  rozpiętośćSkrzydeł: number; // metry
10  prędkośćLotu: number;       // km/h
11  maksWysokość: number;       // metry
12}
13
14// Dinozaur, który potrafi i pływać, i latać (jak Pteranodon)
15type LatającyIPływającyDinozaur = PodstawowyDinozaur & Latający & Pływający;
16
17const pteranodon: LatającyIPływającyDinozaur = {
18  id: 201,
19  nazwa: "Pterri",
20  gatunek: "Pteranodon",
21  wiek: 12,
22
23  // Umiejętności latania
24  rozpiętośćSkrzydeł: 8,
25  prędkośćLotu: 90,
26  maksWysokość: 500,
27
28  // Umiejętności pływania
29  prędkośćPływania: 20,
30  maksGłębokość: 10,
31  wytrzymałośćPodWodą: 3
32};

2. Rozszerzanie istniejących typów

1// Podstawowy interfejs bezpieczeństwa dla wszystkich wybiegów
2interface PodstawowySystemBezpieczeństwa {
3  podwójneOgrodzenie: boolean;
4  monitoringWideo: boolean;
5  czujnikiRuchu: boolean;
6}
7
8// Dodatkowe środki bezpieczeństwa dla drapieżników
9interface ZabezpieczeniaDlaDrapieżników {
10  napięcieElektryczne: number; // wolty
11  grubośćŚcian: number; // cm
12  kopułaZabezpieczająca: boolean;
13}
14
15// Pełny system bezpieczeństwa dla wybiegu drapieżników
16type WybiegDrapieżnika = PodstawowySystemBezpieczeństwa & ZabezpieczeniaDlaDrapieżników;
17
18// Używamy intersection do dodania informacji o paddle
19type WybiegTRex = WybiegDrapieżnika & {
20  obszar: number; // hektary
21  ukształtowanieTerenu: string[];
22  roślinnośćWiarygodna: boolean;
23};
24
25const wybiegRex: WybiegTRex = {
26  // PodstawowySystemBezpieczeństwa
27  podwójneOgrodzenie: true,
28  monitoringWideo: true,
29  czujnikiRuchu: true,
30
31  // ZabezpieczeniaDlaDrapieżników
32  napięcieElektryczne: 10000,
33  grubośćŚcian: 50,
34  kopułaZabezpieczająca: false,
35
36  // Specyficzne dla WybiegTRex
37  obszar: 8,
38  ukształtowanieTerenu: ["wysoka trawa", "wzgórza", "strumień"],
39  roślinnośćWiarygodna: true
40};

3. Łączenie funkcjonalności w złożonych systemach

1// Interfejs systemu obserwacji
2interface SystemObserwacji {
3  kamery: number;
4  rozdzielczość: string;
5  śledzeniePodczerwienią: boolean;
6
7  rozpocznijNagrywanie(): void;
8  zatrzymajNagrywanie(): void;
9}
10
11// Interfejs systemu alarmowego
12interface SystemAlarmowy {
13  sygnałDźwiękowy: boolean;
14  sygnałŚwietlny: boolean;
15  powiadomienieSMS: boolean;
16
17  uruchomAlarm(poziom: number): void;
18  wyłączAlarm(): void;
19}
20
21// Złożony system bezpieczeństwa łączący obie funkcjonalności
22type SystemBezpieczeństwaParku = SystemObserwacji & SystemAlarmowy;
23
24// Implementacja systemu bezpieczeństwa
25class PełnySystemBezpieczeństwa implements SystemBezpieczeństwaParku {
26  // SystemObserwacji
27  kamery: number = 24;
28  rozdzielczość: string = "4K";
29  śledzeniePodczerwienią: boolean = true;
30
31  rozpocznijNagrywanie(): void {
32    console.log("Rozpoczynam nagrywanie ze wszystkich kamer");
33  }
34
35  zatrzymajNagrywanie(): void {
36    console.log("Zatrzymuję nagrywanie");
37  }
38
39  // SystemAlarmowy
40  sygnałDźwiękowy: boolean = true;
41  sygnałŚwietlny: boolean = true;
42  powiadomienieSMS: boolean = true;
43
44  uruchomAlarm(poziom: number): void {
45    console.log(`Uruchamiam alarm poziomu ${poziom}!`);
46    if (this.sygnałDźwiękowy) console.log("Syreny włączone");
47    if (this.sygnałŚwietlny) console.log("Światła ostrzegawcze włączone");
48    if (this.powiadomienieSMS) console.log("Wysyłam powiadomienia SMS do personelu");
49  }
50
51  wyłączAlarm(): void {
52    console.log("Wyłączam wszystkie systemy alarmowe");
53  }
54
55  // Dodatkowe metody specyficzne dla pełnego systemu
56  uruchomProcedurębezpieczeństwa(kodZagrożenia: string): void {
57    console.log(`Inicjuję procedurę bezpieczeństwa: ${kodZagrożenia}`);
58    this.rozpocznijNagrywanie();
59    this.uruchomAlarm(kodZagrożenia === "CZERWONY" ? 3 : 1);
60  }
61}
62
63// Użycie systemu
64const systemBezpieczeństwa = new PełnySystemBezpieczeństwa();
65systemBezpieczeństwa.uruchomProcedurębezpieczeństwa("CZERWONY");

Połączenie union i intersection - zaawansowane przypadki

Prawdziwa potęga TypeScript ujawnia się, gdy łączymy typy union i intersection w bardziej złożone struktury - podobnie jak Dr. Wu łączy DNA różnych gatunków, aby stworzyć zupełnie nowe dinozaury.

1// Podstawowe typy dinozaurów
2interface Dinozaur {
3  id: number;
4  nazwa: string;
5  gatunek: string;
6}
7
8interface LądowyDinozaur {
9  środowisko: "lądowe";
10  prędkośćBiegu: number; // km/h
11}
12
13interface WodnyDinozaur {
14  środowisko: "wodne";
15  prędkośćPływania: number; // km/h
16  maksGłębokość: number; // metry
17}
18
19interface PowietrznyDinozaur {
20  środowisko: "powietrzne";
21  prędkośćLotu: number; // km/h
22  maksWysokość: number; // metry
23}
24
25// Typy dla różnych zdolności
26interface ZdolnościŁowieckie {
27  siłaUgryzienia: number; // PSI
28  strategiaPolowania: "zasadzka" | "pościg" | "stadna";
29}
30
31interface ZdolnościObronneRoślinożercy {
32  pancerz: boolean;
33  rogi: boolean;
34  kolce: boolean;
35  siłaObronna: number; // 1-10
36}
37
38// Złożony typ wykorzystujący union i intersection
39type DinozaurParkowy = Dinozaur &
40  (
41    (LądowyDinozaur & ZdolnościŁowieckie) |
42    (LądowyDinozaur & ZdolnościObronneRoślinożercy) |
43    (WodnyDinozaur & ZdolnościŁowieckie) |
44    (PowietrznyDinozaur & ZdolnościŁowieckie)
45  );
46
47// Przykłady użycia
48const tyranozaur: DinozaurParkowy = {
49  id: 1,
50  nazwa: "Rex",
51  gatunek: "Tyrannosaurus Rex",
52  środowisko: "lądowe",
53  prędkośćBiegu: 30,
54  siłaUgryzienia: 12800,
55  strategiaPolowania: "pościg"
56};
57
58const stegozaur: DinozaurParkowy = {
59  id: 2,
60  nazwa: "Spike",
61  gatunek: "Stegosaurus",
62  środowisko: "lądowe",
63  prędkośćBiegu: 7,
64  pancerz: true,
65  rogi: false,
66  kolce: true,
67  siłaObronna: 8
68};
69
70// Funkcja obsługująca złożone typy
71function analizujDinozaura(dino: DinozaurParkowy): void {
72  console.log(`Analizuję: ${dino.nazwa} (${dino.gatunek})`);
73
74  // Sprawdzamy środowisko
75  if (dino.środowisko === "lądowe") {
76    console.log(`Prędkość biegu: ${dino.prędkośćBiegu} km/h`);
77
78    // Sprawdzamy, czy to drapieżnik czy roślinożerca
79    if ("siłaUgryzienia" in dino) {
80      console.log(`Drapieżnik - siła ugryzienia: ${dino.siłaUgryzienia} PSI`);
81      console.log(`Strategia polowania: ${dino.strategiaPolowania}`);
82    } else if ("siłaObronna" in dino) {
83      console.log("Roślinożerca z mechanizmami obronnymi:");
84      if (dino.pancerz) console.log("- Wyposażony w pancerz");
85      if (dino.rogi) console.log("- Posiada rogi");
86      if (dino.kolce) console.log("- Posiada kolce");
87      console.log(`Siła obronna: ${dino.siłaObronna}/10`);
88    }
89  } else if (dino.środowisko === "wodne") {
90    console.log(`Wodny drapieżnik - prędkość pływania: ${dino.prędkośćPływania} km/h`);
91    console.log(`Maksymalna głębokość: ${dino.maksGłębokość} m`);
92  } else if (dino.środowisko === "powietrzne") {
93    console.log(`Powietrzny drapieżnik - prędkość lotu: ${dino.prędkośćLotu} km/h`);
94    console.log(`Maksymalna wysokość lotu: ${dino.maksWysokość} m`);
95  }
96}
97
98analizujDinozaura(tyranozaur);
99console.log("---");
100analizujDinozaura(stegozaur);

Podsumowanie

Typy union i intersection są jak zaawansowane techniki inżynierii genetycznej Dr. Wu - dają nam niezwykłą moc i elastyczność w projektowaniu złożonych systemów TypeScript.

TypOperatorAnalogia w Parku JurajskimZastosowanie
Union``Wybieg mogący pomieścić różne dinozaury (ale tylko jeden rodzaj jednocześnie)Zmienne, które mogą mieć różne typy
Discriminated Union`` z właściwością dyskryminującąSystem identyfikacji różnych gatunków dinozaurówBezpieczna obsługa różnych wariantów typu
Intersection&Łączenie DNA z różnych dinozaurówŁączenie interfejsów/typów w bardziej złożone struktury

Dr. Wu podsumowuje dzisiejszą lekcję: "TypeScript, podobnie jak nasze laboratorium genetyczne, daje nam ogromne możliwości. Dzięki union i intersection types możemy tworzyć systemy dokładnie dopasowane do naszych potrzeb, łącząc proste elementy w złożone struktury. Jednak pamiętaj - z wielką mocą przychodzi wielka odpowiedzialność. Użyj tej wiedzy mądrze, aby stworzyć bezpieczny i niezawodny park."

Kod do tej lekcji: index.ts
1// Typy union i intersection w Parku Jurajskim
2console.log("Union i Intersection Types\n");
3
4// ===========================================
5// 1. UNION TYPES - typ A lub B
6// ===========================================
7console.log("=== UNION TYPES ===");
8
9// Prosty union type
10type DinosaurDiet = "carnivore" | "herbivore" | "omnivore";
11
12let trexDiet: DinosaurDiet = "carnivore";
13let brachiosaurDiet: DinosaurDiet = "herbivore";
14
15console.log("T-Rex diet:", trexDiet);
16console.log("Brachiosaurus diet:", brachiosaurDiet);
17
18// Union z różnymi typami
19type ID = number | string;
20
21let paddockId: ID = "P-01";
22let dinosaurId: ID = 123;
23
24console.log("Paddock ID:", paddockId);
25console.log("Dinosaur ID:", dinosaurId);
26
27// Union z obiektami
28interface Carnivore {
29  type: "carnivore";
30  huntingStyle: string;
31  preySize: string;
32}
33
34interface Herbivore {
35  type: "herbivore";
36  plantPreference: string;
37  grazingHours: number;
38}
39
40type Dinosaur = Carnivore | Herbivore;
41
42const trex: Carnivore = {
43  type: "carnivore",
44  huntingStyle: "ambush predator",
45  preySize: "large"
46};
47
48const triceratops: Herbivore = {
49  type: "herbivore",
50  plantPreference: "ferns and cycads",
51  grazingHours: 16
52};
53
54// Type guards dla union types
55function describeDiet(dino: Dinosaur): string {
56  if (dino.type === "carnivore") {
57    return `Carnivore: ${dino.huntingStyle}, preys on ${dino.preySize} animals`;
58  } else {
59    return `Herbivore: prefers ${dino.plantPreference}, grazes ${dino.grazingHours}h/day`;
60  }
61}
62
63console.log("\nT-Rex:", describeDiet(trex));
64console.log("Triceratops:", describeDiet(triceratops));
65
66// ===========================================
67// 2. INTERSECTION TYPES - typ A i B
68// ===========================================
69console.log("\n=== INTERSECTION TYPES ===");
70
71// Łączenie typów
72interface HasName {
73  name: string;
74}
75
76interface HasWeight {
77  weight: number;
78}
79
80interface HasDiet {
81  diet: DinosaurDiet;
82}
83
84// Intersection - musi mieć wszystkie właściwości
85type CompleteDinosaur = HasName & HasWeight & HasDiet;
86
87const velociraptor: CompleteDinosaur = {
88  name: "Blue",
89  weight: 350,
90  diet: "carnivore"
91};
92
93console.log("Complete dinosaur:", velociraptor);
94
95// Rozszerzanie interfejsów przez intersection
96interface BasicInfo {
97  id: number;
98  species: string;
99}
100
101interface LocationInfo {
102  paddockId: string;
103  zone: string;
104}
105
106interface HealthInfo {
107  isHealthy: boolean;
108  lastCheckup: Date;
109}
110
111type FullDinosaurInfo = BasicInfo & LocationInfo & HealthInfo;
112
113const rexy: FullDinosaurInfo = {
114  id: 1,
115  species: "Tyrannosaurus Rex",
116  paddockId: "P-01",
117  zone: "Carnivore Zone",
118  isHealthy: true,
119  lastCheckup: new Date()
120};
121
122console.log("\nFull info:", rexy);
123
124// ===========================================
125// 3. Łączenie Union i Intersection
126// ===========================================
127console.log("\n=== UNION + INTERSECTION ===");
128
129interface Swimmer {
130  swimSpeed: number;
131}
132
133interface Runner {
134  runSpeed: number;
135}
136
137interface Flyer {
138  flySpeed: number;
139}
140
141// Dinozaur może pływać LUB latać, ALE musi umieć biegać
142type ActiveDinosaur = Runner & (Swimmer | Flyer);
143
144const mosasaurus: ActiveDinosaur = {
145  runSpeed: 5, // na lądzie powolny
146  swimSpeed: 50 // w wodzie szybki
147};
148
149const pteranodon: ActiveDinosaur = {
150  runSpeed: 10,
151  flySpeed: 80
152};
153
154console.log("Mosasaurus:", mosasaurus);
155console.log("Pteranodon:", pteranodon);
156
157// ===========================================
158// 4. Praktyczne zastosowania
159// ===========================================
160console.log("\n=== PRAKTYCZNE ZASTOSOWANIA ===");
161
162// API Response type
163type SuccessResponse = {
164  status: "success";
165  data: any;
166};
167
168type ErrorResponse = {
169  status: "error";
170  message: string;
171  code: number;
172};
173
174type ApiResponse = SuccessResponse | ErrorResponse;
175
176function handleResponse(response: ApiResponse): void {
177  if (response.status === "success") {
178    console.log("Data received:", response.data);
179  } else {
180    console.log(`Error ${response.code}: ${response.message}`);
181  }
182}
183
184const success: ApiResponse = {
185  status: "success",
186  data: { dinosaurs: [trex, triceratops] }
187};
188
189const error: ApiResponse = {
190  status: "error",
191  message: "Paddock breach detected",
192  code: 503
193};
194
195handleResponse(success);
196handleResponse(error);
197
198// Event types
199interface BaseEvent {
200  timestamp: Date;
201  source: string;
202}
203
204interface FeedingEvent extends BaseEvent {
205  type: "feeding";
206  dinosaurId: number;
207  foodAmount: number;
208}
209
210interface EscapeEvent extends BaseEvent {
211  type: "escape";
212  dinosaurId: number;
213  paddockId: string;
214  severity: "low" | "high";
215}
216
217interface MaintenanceEvent extends BaseEvent {
218  type: "maintenance";
219  paddockId: string;
220  duration: number;
221}
222
223type ParkEvent = FeedingEvent | EscapeEvent | MaintenanceEvent;
224
225function logEvent(event: ParkEvent): void {
226  console.log(`[${event.timestamp.toISOString()}] ${event.source}`);
227
228  switch (event.type) {
229    case "feeding":
230      console.log(`  Feeding dinosaur #${event.dinosaurId}: ${event.foodAmount}kg`);
231      break;
232    case "escape":
233      console.log(`  ESCAPE from paddock ${event.paddockId}! Severity: ${event.severity}`);
234      break;
235    case "maintenance":
236      console.log(`  Maintenance on paddock ${event.paddockId}: ${event.duration}h`);
237      break;
238  }
239}
240
241const feedingEvent: FeedingEvent = {
242  type: "feeding",
243  timestamp: new Date(),
244  source: "Automated System",
245  dinosaurId: 1,
246  foodAmount: 400
247};
248
249const escapeEvent: EscapeEvent = {
250  type: "escape",
251  timestamp: new Date(),
252  source: "Security Alert",
253  dinosaurId: 1,
254  paddockId: "P-01",
255  severity: "high"
256};
257
258console.log("\nEvent log:");
259logEvent(feedingEvent);
260logEvent(escapeEvent);
261
262// ===========================================
263// 5. Podsumowanie
264// ===========================================
265console.log("\n=== PODSUMOWANIE ===");
266console.log("Union Types (|) - wartość może być jednym z typów");
267console.log("Intersection Types (&) - wartość musi spełniać wszystkie typy");
268console.log("Type Guards - sprawdzanie typu w runtime");
269console.log("Discriminated Unions - rozróżnianie po polu");
270
271console.log("\nUnion i Intersection Types opanowane!");

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Co oznacza typ string | number w TypeScript?

  2. 2. Co robi typ A & B (intersection type)?

Zadania praktyczne w grze

  • Edytor kodu

    Stwórz typ union DietType = 'herbivore' | 'carnivore' | 'omnivore' i intersection type AquaticDino = Dinosaur & SwimmingAbility.

  • Układanie w poziomie

    Ułóż elementy type alias:

  • Klikanie w kolejności

    Ułóż elementy definicji union type:

  • Układanie w pionie

    Uporządkuj kroki zawężania (narrowing) typu union w TypeScript:

Przydatne artykuły