Witaj ponownie w Parku Jurajskim! Po zapoznaniu się z podstawowymi typami danych w TypeScript, jesteśmy gotowi, aby przejść do bardziej zaawansowanych struktur. W dzisiejszej lekcji Dr. Wu zabierze nas do laboratorium, gdzie będziemy eksperymentować z bardziej złożonymi typami danych.
Tak jak w Parku Jurajskim nie wystarczy znać pojedynczych gatunków - trzeba rozumieć, jak funkcjonują całe ekosystemy i hierarchie dinozaurów - tak w TypeScript nie wystarczy znać tylko typy podstawowe. Musimy nauczyć się organizować dane w bardziej złożone struktury.
Tablice w TypeScript są jak wybiegi w Parku Jurajskim - służą do przechowywania kolekcji podobnych elementów. Możemy zdefiniować typ tablicy na dwa sposoby:
1// Definiowanie tablicy dinozaurów
2let dinozaury: string[] = ["Tyrannosaurus", "Velociraptor", "Triceratops"];
3
4// Alternatywna notacja
5let dinozauryAlt: Array<string> = ["Brachiosaurus", "Stegosaurus", "Ankylosaurus"];
6
7// Tablica liczb - np. wagi dinozaurów w kilogramach
8let wagi: number[] = [7500, 350, 8500, 35000, 5500];
9
10// Dostęp do elementów tablicy
11console.log(`Pierwszy dinozaur: ${dinozaury[0]}`); // Tyrannosaurus
12console.log(`Liczba dinozaurów: ${dinozaury.length}`); // 3
13
14// Dodawanie do tablicy
15dinozaury.push("Spinosaurus");
16console.log(`Teraz mamy ${dinozaury.length} dinozaurów`); // 4
17
18// Iteracja po tablicy
19dinozaury.forEach(dino => {
20 console.log(`Badanie zachowania: ${dino}`);
21});Tablice mogą również przechowywać bardziej złożone obiekty:
1// Definiowanie interfejsu dla obiektu dinozaura
2interface Dinozaur {
3 id: number;
4 nazwa: string;
5 gatunek: string;
6 jestDrapieżnikiem: boolean;
7 wiekMlnLat: number;
8}
9
10// Tablica obiektów dinozaurów
11const kolekcjaOkazów: Dinozaur[] = [
12 { id: 1, nazwa: "Rex", gatunek: "Tyrannosaurus", jestDrapieżnikiem: true, wiekMlnLat: 68 },
13 { id: 2, nazwa: "Blue", gatunek: "Velociraptor", jestDrapieżnikiem: true, wiekMlnLat: 75 },
14 { id: 3, nazwa: "Trixie", gatunek: "Triceratops", jestDrapieżnikiem: false, wiekMlnLat: 68 }
15];
16
17// Filtrowanie tablicy - znajdź wszystkie drapieżniki
18const drapieżniki = kolekcjaOkazów.filter(dino => dino.jestDrapieżnikiem);
19console.log(`Liczba drapieżników: ${drapieżniki.length}`); // 2
20
21// Przekształcanie tablicy - pozyskaj tylko nazwy dinozaurów
22const nazwyDinozaurów = kolekcjaOkazów.map(dino => dino.nazwa);
23console.log(`Nazwy okazów: ${nazwyDinozaurów.join(", ")}`); // "Rex, Blue, Trixie"Tablice wielowymiarowe można wykorzystać do reprezentowania bardziej złożonych danych, takich jak mapa wybiegów w Parku Jurajskim:
1// Dwuwymiarowa tablica reprezentująca mapę Parku Jurajskiego
2// 0 = teren niedostępny, 1 = ścieżka, 2 = wybieg roślinożerców, 3 = wybieg drapieżników
3const mapaParkuJurajskiego: number[][] = [
4 [0, 0, 2, 2, 2, 0, 0],
5 [0, 1, 1, 1, 1, 1, 0],
6 [0, 1, 3, 3, 3, 1, 0],
7 [0, 1, 1, 1, 1, 1, 0],
8 [0, 0, 2, 2, 2, 0, 0]
9];
10
11// Sprawdzanie, co znajduje się na danej pozycji
12function sprawdźTeren(x: number, y: number): string {
13 const teren = mapaParkuJurajskiego[y][x];
14 switch (teren) {
15 case 0: return "Teren niedostępny";
16 case 1: return "Ścieżka dla zwiedzających";
17 case 2: return "Wybieg dinozaurów roślinożernych";
18 case 3: return "UWAGA! Wybieg drapieżników!";
19 default: return "Nieznany teren";
20 }
21}
22
23console.log(sprawdźTeren(2, 2)); // "UWAGA! Wybieg drapieżników!"Krotki (Tuple) to specjalny rodzaj tablicy, w której znamy dokładną liczbę elementów i ich typy. To jak transport dinozaurów - musi być ściśle określony typ pojazdu i specjalne zabezpieczenia odpowiednie dla konkretnego gatunku.
1// Krotka reprezentująca dane pracownika: [id, imię, stanowisko, poziom dostępu]
2type PracownikParku = [number, string, string, number];
3
4const pracownicy: PracownikParku[] = [
5 [1, "John Hammond", "Dyrektor", 5],
6 [2, "Dr. Alan Grant", "Paleontolog", 4],
7 [3, "Dr. Ellie Sattler", "Paleobotanik", 4],
8 [4, "Dennis Nedry", "Programista", 3]
9];
10
11// Krotka z różnymi typami elementów
12// Format: [kod DNA, gatunek, wiek w latach, czy jest drapieżnikiem]
13type KodGenetyczny = [string, string, number, boolean];
14
15const kodTRex: KodGenetyczny = ["ACGTTCAGC", "Tyrannosaurus Rex", 68, true];
16
17// Destrukturyzacja krotki
18const [dnaKod, gatunek, wiek, drapieżnik] = kodTRex;
19console.log(`DNA: ${dnaKod}, Gatunek: ${gatunek}`);
20
21// Opcjonalne elementy krotki (od TypeScript 3.0)
22// Format: [id, nazwa, opcjonalny tag RFID]
23type OkazMuzealny = [number, string, string?];
24
25const okazDinozaura: OkazMuzealny = [42, "Czaszka Velociraptora"];
26const okazZTagiem: OkazMuzealny = [43, "Jajo dinozaura", "RFID-J-43"];Typy wyliczeniowe (Enum) w TypeScript są jak kategorie bezpieczeństwa w Parku Jurajskim - pomagają definiować zbiór nazwanych stałych, z których można korzystać w kodzie.
1// Definiowanie typu wyliczeniowego dla kategorii zagrożeń
2enum KategoriaZagrożenia {
3 Niskie, // 0
4 Umiarkowane, // 1
5 Wysokie, // 2
6 Krytyczne, // 3
7 PoziomCzerwony // 4
8}
9
10// Użycie enum
11let zagrożenieWybieguTRex: KategoriaZagrożenia = KategoriaZagrożenia.Wysokie;
12
13if (zagrożenieWybieguTRex >= KategoriaZagrożenia.Wysokie) {
14 console.log("Zalecane podwójne ogrodzenie elektryczne!");
15}
16
17// Dostęp po wartości
18const kategoriaOpis = (poziom: KategoriaZagrożenia): string => {
19 switch (poziom) {
20 case KategoriaZagrożenia.Niskie: return "Standardowe środki ostrożności";
21 case KategoriaZagrożenia.Umiarkowane: return "Zwiększona czujność";
22 case KategoriaZagrożenia.Wysokie: return "Podwójne zabezpieczenia";
23 case KategoriaZagrożenia.Krytyczne: return "Zakaz wstępu dla zwiedzających";
24 case KategoriaZagrożenia.PoziomCzerwony: return "Ewakuacja parku!";
25 default: return "Nieznany poziom zagrożenia";
26 }
27};
28
29console.log(kategoriaOpis(zagrożenieWybieguTRex)); // "Podwójne zabezpieczenia"
30
31// Enum z określonymi wartościami
32enum StatusDinozaura {
33 Nieaktywny = 0,
34 OgraniczonaAktywność = 5,
35 Aktywny = 10,
36 BardzoAktywny = 15,
37 NiezbędnaInterwencja = 20
38}
39
40let statusRexT: StatusDinozaura = StatusDinozaura.BardzoAktywny;
41console.log(`Poziom aktywności T-Rex: ${statusRexT}`); // 15
42
43// Enum tekstowy
44enum GatunekDinozaura {
45 TRex = "Tyrannosaurus Rex",
46 Raptor = "Velociraptor",
47 Tric = "Triceratops",
48 Stego = "Stegosaurus",
49 Brach = "Brachiosaurus"
50}
51
52let ulubieniecPubliczności: GatunekDinozaura = GatunekDinozaura.TRex;
53console.log(`Dzisiejsza atrakcja: ${ulubieniecPubliczności}`); // "Tyrannosaurus Rex"Const Enum to optymalizacja TypeScript, która eliminuje obiekt enum w czasie kompilacji, zastępując odwołania do enum bezpośrednio wartościami.
1// Zdefiniowanie Const Enum
2const enum StrefaBezpieczeństwa {
3 Publiczna = 1,
4 Pracownicy = 2,
5 OgraniczonyDostęp = 3,
6 Laboratoria = 4,
7 Zagrożenie = 5
8}
9
10// Wykorzystanie Const Enum
11function sprawdźUprawnienia(poziomDostępu: number, wymaganaStrefa: StrefaBezpieczeństwa): boolean {
12 return poziomDostępu >= wymaganaStrefa;
13}
14
15// Wywołanie z wartościami enum
16const dostępDrWu = sprawdźUprawnienia(5, StrefaBezpieczeństwa.Laboratoria); // true
17const dostępPracownika = sprawdźUprawnienia(2, StrefaBezpieczeństwa.Zagrożenie); // falsePrzyjrzyjmy się, jak możemy wykorzystać te typy złożone do zbudowania systemu zarządzania Parkiem Jurajskim:
1// Definiowanie interfejsów i typów
2enum StatusZdrowia {
3 Doskonały = "doskonały",
4 Dobry = "dobry",
5 Wymagauwagi = "wymaga uwagi",
6 Chory = "chory",
7 Krytyczny = "krytyczny"
8}
9
10enum KlasyfikacjaDiety {
11 Roślinożerca = "roślinożerca",
12 Wszystkożerca = "wszystkożerca",
13 Drapieżnik = "drapieżnik"
14}
15
16interface DaneWitalne {
17 temperatura: number;
18 tętno: number;
19 ciśnienieKrwi: [number, number]; // Krotka [skurczowe, rozkurczowe]
20 poziomStresu: number; // 1-10
21}
22
23interface Dinozaur {
24 id: number;
25 nazwa: string;
26 gatunek: string;
27 klasyfikacjaDiety: KlasyfikacjaDiety;
28 wiek: number;
29 waga: number;
30 status: StatusZdrowia;
31 daneWitalne: DaneWitalne;
32 aktywnośćDziennaArray: number[]; // Poziom aktywności w okresach 3-godzinnych (8 wartości dla pełnej doby)
33}
34
35// Tworzenie systemu zarządzania dinozaurami
36class SystemZarządzaniaDinozaurami {
37 private dinozaury: Dinozaur[] = [];
38
39 dodajDinozaura(dino: Dinozaur): void {
40 this.dinozaury.push(dino);
41 console.log(`Dodano dinozaura: ${dino.nazwa} (${dino.gatunek})`);
42 }
43
44 znajdźDinozaura(id: number): Dinozaur | undefined {
45 return this.dinozaury.find(d => d.id === id);
46 }
47
48 aktualizujStatusZdrowia(id: number, nowyStatus: StatusZdrowia): boolean {
49 const dino = this.znajdźDinozaura(id);
50 if (dino) {
51 dino.status = nowyStatus;
52 console.log(`Zaktualizowano status zdrowia ${dino.nazwa} na: ${nowyStatus}`);
53 return true;
54 }
55 return false;
56 }
57
58 pobierzDrapieżniki(): Dinozaur[] {
59 return this.dinozaury.filter(d => d.klasyfikacjaDiety === KlasyfikacjaDiety.Drapieżnik);
60 }
61
62 pobierzDinozauryWymagająceUwagi(): Dinozaur[] {
63 return this.dinozaury.filter(d =>
64 d.status === StatusZdrowia.Wymagauwagi ||
65 d.status === StatusZdrowia.Chory ||
66 d.status === StatusZdrowia.Krytyczny
67 );
68 }
69
70 obliczŚrednięAktywności(id: number): number | null {
71 const dino = this.znajdźDinozaura(id);
72 if (dino) {
73 const suma = dino.aktywnośćDziennaArray.reduce((acc, val) => acc + val, 0);
74 return suma / dino.aktywnośćDziennaArray.length;
75 }
76 return null;
77 }
78
79 przygotujRaportDzienny(): [string, number, StatusZdrowia][] {
80 // Zwraca krotkę [nazwa, id, status] dla każdego dinozaura
81 return this.dinozaury.map(d => [d.nazwa, d.id, d.status]);
82 }
83}
84
85// Przykładowe użycie
86const systemJP = new SystemZarządzaniaDinozaurami();
87
88// Dodanie dinozaurów do systemu
89systemJP.dodajDinozaura({
90 id: 1,
91 nazwa: "Rexy",
92 gatunek: "Tyrannosaurus Rex",
93 klasyfikacjaDiety: KlasyfikacjaDiety.Drapieżnik,
94 wiek: 7,
95 waga: 8000,
96 status: StatusZdrowia.Dobry,
97 daneWitalne: {
98 temperatura: 38.2,
99 tętno: 70,
100 ciśnienieKrwi: [140, 90],
101 poziomStresu: 3
102 },
103 aktywnośćDziennaArray: [2, 1, 0, 0, 1, 3, 5, 2]
104});
105
106systemJP.dodajDinozaura({
107 id: 2,
108 nazwa: "Blue",
109 gatunek: "Velociraptor",
110 klasyfikacjaDiety: KlasyfikacjaDiety.Drapieżnik,
111 wiek: 3,
112 waga: 350,
113 status: StatusZdrowia.Doskonały,
114 daneWitalne: {
115 temperatura: 39.1,
116 tętno: 95,
117 ciśnienieKrwi: [130, 85],
118 poziomStresu: 2
119 },
120 aktywnośćDziennaArray: [4, 2, 1, 0, 2, 5, 6, 3]
121});
122
123systemJP.dodajDinozaura({
124 id: 3,
125 nazwa: "Spike",
126 gatunek: "Stegosaurus",
127 klasyfikacjaDiety: KlasyfikacjaDiety.Roślinożerca,
128 wiek: 12,
129 waga: 5000,
130 status: StatusZdrowia.Wymagauwagi,
131 daneWitalne: {
132 temperatura: 37.5,
133 tętno: 50,
134 ciśnienieKrwi: [125, 80],
135 poziomStresu: 6
136 },
137 aktywnośćDziennaArray: [3, 3, 2, 1, 3, 2, 2, 1]
138});
139
140// Korzystanie z systemu
141const drapieżniki = systemJP.pobierzDrapieżniki();
142console.log(`Liczba drapieżników w parku: ${drapieżniki.length}`);
143
144const wymagającyUwagi = systemJP.pobierzDinozauryWymagająceUwagi();
145console.log(`Liczba dinozaurów wymagających uwagi: ${wymagającyUwagi.length}`);
146
147// Przykład raportu dziennego (tablica krotek)
148const raportDzienny = systemJP.przygotujRaportDzienny();
149console.log("
150Dzienny raport stanu dinozaurów:");
151raportDzienny.forEach(([nazwa, id, status]) => {
152 console.log(`- ${nazwa} (ID: ${id}): ${status}`);
153});
154
155// Przykład aktualizacji statusu
156systemJP.aktualizujStatusZdrowia(1, StatusZdrowia.Wymagauwagi);| Typ | Zastosowanie w Parku Jurajskim | Przykład | |-----|----------------------------------|----------| | Array | Kolekcje podobnych elementów, np. lista dinozaurów | string[], Dinozaur[] | | Multidimensional Array | Reprezentacja przestrzenna, np. mapa parku | number[][] | | Tuple | Stałe struktury z określonymi typami i rozmiarami, np. dane genetyczne | [string, string, number, boolean] | | Enum | Zdefiniowane kategorie, np. poziomy zagrożenia | enum KategoriaZagrożenia {...} | | Const Enum | Zoptymalizowane enumy dla wydajności | const enum StrefaBezpieczeństwa {...} |
Pamiętaj, że dobór odpowiednich typów danych w projekcie jest jak projektowanie bezpiecznych i efektywnych wybiegów w Parku Jurajskim - dobre projektowanie na początku zaoszczędzi wielu problemów w przyszłości!
Dr. Wu zawsze powtarza: "Precyzyjna kontrola typów to podstawa sukcesu - zarówno w laboratorium genetycznym, jak i w kodzie TypeScript."