Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Typy złożone (array, tuple, enum)

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.

Typy tablicowe (Array)

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

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!"

Tablice o różnych typach elementów - Tuple (krotki)

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)

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

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); // false

Praktyczne zastosowanie typów złożonych

Przyjrzyjmy 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);

Podsumowanie typów złożonych

| 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."

Ir a CodeWorlds