Kurs JavaScript i TypeScript · Moduł 6: Podstawy TypeScript
Type aliases
W tej lekcji10
Witaj ponownie w laboratorium genetycznym Parku Jurajskiego! Dr. Henry Wu dziś zapozna nas z niezwykle przydatnym mechanizmem TypeScript - aliasami typów (type aliases). Tak jak naukowcy w parku używają skrótowych nazw dla złożonych sekwencji genetycznych, tak programiści używają aliasów typów, aby uprościć złożone definicje typów.
Czym są aliasy typów (type aliases)?
Alias typu to po prostu nazwa, którą nadajemy istniejącemu typowi. Możemy aliasować zarówno proste, jak i złożone typy, co czyni kod bardziej czytelnym i łatwiejszym w utrzymaniu. To jak nazywanie różnych mieszanek DNA, aby łatwiej się do nich odwoływać podczas pracy laboratoryjnej.
Podstawowa składnia
Aliasy typów definiujemy za pomocą słowa kluczowego type:
1// Prosty alias typu dla string
2type IDGatunku = string;
3
4// Używanie aliasu
5const tRexID: IDGatunku = "TREX-01";
6const velociraptorID: IDGatunku = "VELOC-01";Aliasy dla typów prymitywnych
Aliasy typów mogą być stosowane do prostych typów, co może być pomocne dla dokumentacji i intencji kodu:
1// Aliasy dla prostych typów
2type PoziomBezpieczeństwa = number;
3type NazwaGatunku = string;
4type CzyDrapieżnik = boolean;
5
6// Funkcja wykorzystująca aliasy typów
7function ustawPoziomOgrodzenia(gatunek: NazwaGatunku, drapieżnik: CzyDrapieżnik): PoziomBezpieczeństwa {
8 if (drapieżnik) {
9 if (gatunek === "Tyrannosaurus") return 5;
10 if (gatunek === "Velociraptor") return 4;
11 return 3; // Inne drapieżniki
12 } else {
13 return 2; // Roślinożercy
14 }
15}
16
17const poziomTRex = ustawPoziomOgrodzenia("Tyrannosaurus", true); // 5
18console.log(`Poziom bezpieczeństwa dla T-Rex: ${poziomTRex}`);Aliasy dla typów złożonych
Aliasy typów stają się szczególnie przydatne przy definiowaniu złożonych typów, takich jak obiekty, unie czy tablice:
1// Alias dla typu obiektu (podobnie jak interfejs)
2type Dinozaur = {
3 id: string;
4 nazwa: string;
5 gatunek: string;
6 wiek: number;
7 waga: number;
8 drapieżnik: boolean;
9};
10
11// Alias dla unii typów - różne identyfikatory
12type IDDinozaura = string | number;
13
14// Alias dla krotki (tuple) - współrzędne GPS z opisem
15type Lokalizacja = [number, number, string];
16
17// Alias dla tablicy
18type ListaGatunków = string[];
19
20// Alias dla literału obiektu z opcjonalnymi polami
21type StatusZdrowia = {
22 ogólnyStanZdrowia: "doskonały" | "dobry" | "średni" | "słaby" | "krytyczny";
23 temperatura?: number;
24 tętno?: number;
25 priorytetLeczenia?: 1 | 2 | 3 | 4 | 5;
26 notatki?: string;
27};
28
29// Tworzenie obiektów na podstawie aliasów typów
30const rexLokalizacja: Lokalizacja = [35.6895, 139.6917, "Wybieg T-Rex, północne ogrodzenie"];
31const gatunkiWParku: ListaGatunków = ["Tyrannosaurus", "Velociraptor", "Triceratops", "Brachiosaurus"];
32
33const statusRex: StatusZdrowia = {
34 ogólnyStanZdrowia: "dobry",
35 temperatura: 38.2,
36 priorytetLeczenia: 2,
37 notatki: "Ostatnio nieco mniejszy apetyt"
38};
39
40// Funkcja pracująca na aliasie typu
41function przygotujRaportDinozaura(dino: Dinozaur, status: StatusZdrowia, lokalizacja: Lokalizacja): string {
42 const [lat, lng, opis] = lokalizacja;
43
44 return `
45 Raport o dinozaurze:
46 ID: ${dino.id}
47 Nazwa: ${dino.nazwa}
48 Gatunek: ${dino.gatunek}
49 Wiek: ${dino.wiek} lat
50 Waga: ${dino.waga} kg
51 Drapieżnik: ${dino.drapieżnik ? "Tak" : "Nie"}
52
53 Status zdrowia: ${status.ogólnyStanZdrowia}
54 ${status.temperatura ? `Temperatura: ${status.temperatura}°C` : ""}
55 ${status.tętno ? `Tętno: ${status.tętno} uderzeń/min` : ""}
56
57 Lokalizacja: ${opis} (${lat}, ${lng})
58 `;
59}Aliasy z generycznymi typami
Aliasy typów mogą również być generyczne, co daje nam jeszcze większą elastyczność:
1// Generyczny alias typu dla danych z systemów monitoringu
2type DaneMonitoringu<T> = {
3 czasPomiaru: Date;
4 wartość: T;
5 jednostka: string;
6 prawidłowy: boolean;
7};
8
9// Używanie generycznego aliasu typu dla różnych rodzajów pomiarów
10type PomiarTemperatury = DaneMonitoringu<number>;
11type PomiarAktywności = DaneMonitoringu<"niska" | "średnia" | "wysoka">;
12type PomiarPoziomuStresu = DaneMonitoringu<1 | 2 | 3 | 4 | 5>;
13
14// Funkcja analizująca dane z monitoringu
15function analizujDane<T>(dane: DaneMonitoringu<T>): void {
16 console.log(`Pomiar z ${dane.czasPomiaru.toISOString()}`);
17 console.log(`Wartość: ${dane.wartość} ${dane.jednostka}`);
18 console.log(`Status: ${dane.prawidłowy ? "Prawidłowy" : "Wymaga uwagi"}`);
19}
20
21// Przykładowe użycie
22const temperaturaWody: PomiarTemperatury = {
23 czasPomiaru: new Date(),
24 wartość: 24.5,
25 jednostka: "°C",
26 prawidłowy: true
27};
28
29const poziomAktywnościTRex: PomiarAktywności = {
30 czasPomiaru: new Date(),
31 wartość: "wysoka",
32 jednostka: "poziom aktywności",
33 prawidłowy: false // Wymaga uwagi, ponieważ T-Rex jest zbyt aktywny
34};
35
36analizujDane(temperaturaWody);
37analizujDane(poziomAktywnościTRex);Rekursywne aliasy typów
Aliasy typów mogą być rekursywne, co przydaje się przy modelowaniu struktur drzewiastych, takich jak hierarchie gatunków czy struktury organizacyjne parku:
1// Rekursywny alias typu dla hierarchii kategorii dinozaurów
2type KategoriaDinozaurów = {
3 nazwa: string;
4 opis?: string;
5 podkategorie?: KategoriaDinozaurów[];
6};
7
8// Tworzenie hierarchii kategorii
9const taksonomia: KategoriaDinozaurów = {
10 nazwa: "Dinozaury",
11 opis: "Główna klasyfikacja dinozaurów w Parku Jurajskim",
12 podkategorie: [
13 {
14 nazwa: "Teropody",
15 opis: "Mięsożerne, dwunożne dinozaury",
16 podkategorie: [
17 {
18 nazwa: "Tyranozaury",
19 podkategorie: [
20 { nazwa: "Tyrannosaurus Rex" }
21 ]
22 },
23 {
24 nazwa: "Deinonychozaury",
25 podkategorie: [
26 { nazwa: "Velociraptor" },
27 { nazwa: "Deinonychus" }
28 ]
29 }
30 ]
31 },
32 {
33 nazwa: "Zauropody",
34 opis: "Duże, czworonożne roślinożercy o długiej szyi",
35 podkategorie: [
36 { nazwa: "Brachiosaurus" },
37 { nazwa: "Diplodocus" }
38 ]
39 }
40 ]
41};
42
43// Funkcja do renderowania drzewa taksonomii
44function wyświetlTaksonomię(kategoria: KategoriaDinozaurów, poziom: number = 0): void {
45 const wcięcie = " ".repeat(poziom);
46 console.log(`${wcięcie}${kategoria.nazwa}`);
47
48 if (kategoria.opis) {
49 console.log(`${wcięcie} Opis: ${kategoria.opis}`);
50 }
51
52 if (kategoria.podkategorie && kategoria.podkategorie.length > 0) {
53 kategoria.podkategorie.forEach(podkategoria => {
54 wyświetlTaksonomię(podkategoria, poziom + 1);
55 });
56 }
57}
58
59wyświetlTaksonomię(taksonomia);Aliasy typów vs. interfejsy
Aliasy typów są często porównywane z interfejsami, ponieważ w wielu przypadkach można ich używać zamiennie. Jednak istnieją między nimi pewne kluczowe różnice:
1// Definicja struktury dinozaura używając interfejsu
2interface DinozaurInterface {
3 id: string;
4 nazwa: string;
5 gatunek: string;
6}
7
8// Równoważna definicja używając aliasu typu
9type DinozaurType = {
10 id: string;
11 nazwa: string;
12 gatunek: string;
13};
14
15// Obie działają podobnie przy podstawowym użyciu
16const dino1: DinozaurInterface = { id: "001", nazwa: "Rex", gatunek: "Tyrannosaurus" };
17const dino2: DinozaurType = { id: "002", nazwa: "Blue", gatunek: "Velociraptor" };Główne różnice między aliasami typów a interfejsami
Rozszerzalność:
- Interfejsy mogą być rozszerzane przez deklarowanie ich wielokrotnie
- Aliasy typów nie mogą być "otwarte" - raz zdefiniowany alias nie może być później rozszerzony
1// Interfejs można rozszerzać przez wielokrotną deklarację 2interface ZwierzęInterface { 3 id: string; 4 gatunek: string; 5} 6 7// Dodajemy nowe pola do istniejącego interfejsu 8interface ZwierzęInterface { 9 wiek: number; 10 waga: number; 11} 12 13// Teraz ZwierzęInterface ma wszystkie cztery pola 14const zwierzę: ZwierzęInterface = { 15 id: "001", 16 gatunek: "Tyrannosaurus", 17 wiek: 7, 18 waga: 7000 19}; 20 21// Aliasu typu nie można rozszerzyć w ten sposób 22type ZwierzęType = { 23 id: string; 24 gatunek: string; 25} 26 27// To spowoduje błąd: Duplicate identifier 'ZwierzęType' 28// type ZwierzęType = { 29// wiek: number; 30// waga: number; 31// }Złożone typy:
- Aliasy typów mogą reprezentować bezpośrednio unie, przecięcia i inne zaawansowane typy
- Interfejsy są bardziej ukierunkowane na definiowanie kształtu obiektów
1// Możliwe tylko z aliasami typów 2type StatusBezpieczeństwa = "normalny" | "podwyższony" | "zagrożenie"; 3type WspółrzędneGPS = [number, number]; 4type IDZwierzęcia = string | number; 5 6// Z interfejsami byłoby to bardziej kłopotliweInterfejsy dla klas:
- Interfejsy są naturalnym wyborem do definiowania kontraktów, które klasy muszą implementować
- Aliasy typów są bardziej elastyczne dla definiowania złożonych typów
1// Interfejs dla klasy 2interface SystemMonitoringu { 3 uruchom(): void; 4 zatrzymaj(): void; 5 pobierzStatus(): string; 6} 7 8// Klasa implementująca interfejs 9class MonitoringWybiegów implements SystemMonitoringu { 10 uruchom() { console.log("Uruchomiono monitoring wybiegów"); } 11 zatrzymaj() { console.log("Zatrzymano monitoring wybiegów"); } 12 pobierzStatus() { return "Aktywny"; } 13}
Łączenie aliasów typów z innymi funkcjami TypeScript
Aliasy typów mogą być łączone z innymi funkcjami TypeScript, tworząc potężne abstrakcje:
1// Łączenie z typami union
2type DaneDinozaura =
3 | { typ: "podstawowe"; id: string; gatunek: string }
4 | { typ: "rozszerzone"; id: string; gatunek: string; wiek: number; waga: number }
5 | { typ: "pełne"; id: string; gatunek: string; wiek: number; waga: number; historia: string[]; statusZdrowia: string };
6
7// Funkcja przetwarzająca różne poziomy danych
8function przetwórzDaneDinozaura(dane: DaneDinozaura): void {
9 console.log(`Przetwarzanie danych dla ID: ${dane.id}, gatunek: ${dane.gatunek}`);
10
11 // Używamy discriminated union do określenia typu danych
12 switch (dane.typ) {
13 case "podstawowe":
14 console.log("Przetwarzanie podstawowych danych");
15 break;
16 case "rozszerzone":
17 console.log(`Wiek: ${dane.wiek}, Waga: ${dane.waga} kg`);
18 break;
19 case "pełne":
20 console.log(`Wiek: ${dane.wiek}, Waga: ${dane.waga} kg`);
21 console.log(`Historia: ${dane.historia.join(", ")}`);
22 console.log(`Status zdrowia: ${dane.statusZdrowia}`);
23 break;
24 }
25}
26
27// Przykłady użycia
28const podst: DaneDinozaura = {
29 typ: "podstawowe",
30 id: "TRX-001",
31 gatunek: "Tyrannosaurus"
32};
33
34const rozszerz: DaneDinozaura = {
35 typ: "rozszerzone",
36 id: "VEL-001",
37 gatunek: "Velociraptor",
38 wiek: 4,
39 waga: 150
40};
41
42const pełne: DaneDinozaura = {
43 typ: "pełne",
44 id: "TRI-001",
45 gatunek: "Triceratops",
46 wiek: 10,
47 waga: 8000,
48 historia: ["Narodziny: 2013", "Transfer z Lokacji B: 2016", "Złamane rogi: 2018", "Rekonwalescencja: 2019"],
49 statusZdrowia: "Dobry"
50};
51
52przetwórzDaneDinozaura(podst);
53przetwórzDaneDinozaura(rozszerz);
54przetwórzDaneDinozaura(pełne);Łączenie typów utility z aliasami typów
TypeScript oferuje wbudowane typy utility, które można łączyć z aliasami typów, co daje nam jeszcze większe możliwości modelowania danych:
1// Podstawowy interfejs dla dinozaura
2interface Dinozaur {
3 id: string;
4 nazwa: string;
5 gatunek: string;
6 wiek: number;
7 waga: number;
8 płeć: "samiec" | "samica";
9 drapieżnik: boolean;
10 aktywnyNocą: boolean;
11 statusZdrowia: "doskonały" | "dobry" | "wymaga uwagi" | "chory" | "krytyczny";
12}
13
14// Aliasy typów z wykorzystaniem utility types
15
16// Typ tylko do odczytu - użyteczny dla danych, które nie powinny być modyfikowane
17type DinozaurTylkoDoOdczytu = Readonly<Dinozaur>;
18
19// Typ z wybranymi polami - użyteczny dla częściowych danych
20type DinozaurPodstawowy = Pick<Dinozaur, "id" | "nazwa" | "gatunek">;
21
22// Typ z pominięciem niektórych pól - użyteczny gdy chcemy wykluczyć pewne dane
23type DinozaurBezStatusu = Omit<Dinozaur, "statusZdrowia">;
24
25// Typ z opcjonalnymi polami - przydatny do częściowych aktualizacji
26type DinozaurCzęściowy = Partial<Dinozaur>;
27
28// Typ z wymaganymi polami - wymuszanie, aby wszystkie pola były zdefiniowane
29type DinozaurWymagane = Required<Dinozaur>;
30
31// Typ mapujący rekordy - przydatny dla kolekcji indeksowanych kluczem
32type BazaDanychDinozaurów = Record<string, Dinozaur>;
33
34// Przykłady użycia
35const rexDoOdczytu: DinozaurTylkoDoOdczytu = {
36 id: "TRX-001",
37 nazwa: "Rex",
38 gatunek: "Tyrannosaurus",
39 wiek: 7,
40 waga: 7000,
41 płeć: "samica",
42 drapieżnik: true,
43 aktywnyNocą: false,
44 statusZdrowia: "dobry"
45};
46
47// rexDoOdczytu.wiek = 8; // Błąd: Cannot assign to 'wiek' because it is a read-only property
48
49const rexPodstawowy: DinozaurPodstawowy = {
50 id: "TRX-001",
51 nazwa: "Rex",
52 gatunek: "Tyrannosaurus"
53};
54
55// Częściowa aktualizacja danych
56function aktualizujDaneDinozaura(id: string, dane: DinozaurCzęściowy): void {
57 console.log(`Aktualizacja danych dla dinozaura ${id}`);
58 console.log(dane);
59 // W rzeczywistej aplikacji aktualizowalibyśmy dane w bazie
60}
61
62aktualizujDaneDinozaura("TRX-001", {
63 wiek: 8,
64 waga: 7200,
65 statusZdrowia: "wymaga uwagi"
66});
67
68// Baza danych dinozaurów
69const bazaDanych: BazaDanychDinozaurów = {
70 "TRX-001": {
71 id: "TRX-001",
72 nazwa: "Rex",
73 gatunek: "Tyrannosaurus",
74 wiek: 7,
75 waga: 7000,
76 płeć: "samica",
77 drapieżnik: true,
78 aktywnyNocą: false,
79 statusZdrowia: "dobry"
80 },
81 "VEL-001": {
82 id: "VEL-001",
83 nazwa: "Blue",
84 gatunek: "Velociraptor",
85 wiek: 4,
86 waga: 150,
87 płeć: "samica",
88 drapieżnik: true,
89 aktywnyNocą: true,
90 statusZdrowia: "doskonały"
91 }
92};
93
94console.log(`Liczba dinozaurów w bazie: ${Object.keys(bazaDanych).length}`);Praktyczny przykład modelu danych Parku Jurajskiego
Zobaczmy teraz, jak możemy użyć aliasów typów wraz z innymi funkcjami TypeScript do stworzenia kompleksowego modelu danych dla systemu zarządzania Parkiem Jurajskim:
1// Bazowe typy
2type ID = string;
3type Koordynaty = [number, number];
4type PoziomDostępu = 1 | 2 | 3 | 4 | 5;
5type StatusAktywności = "aktywny" | "nieaktywny" | "w trakcie konserwacji";
6type StatusZdrowia = "doskonały" | "dobry" | "wymaga uwagi" | "chory" | "krytyczny";
7
8// Typy dinozaurów
9type GrupaTaksonomiczna = "teropody" | "zauropody" | "ceratopsy" | "stegozaury" | "ankylozaury";
10
11type KlasaDiety = "roślinożerca" | "mięsożerca" | "wszystkożerca";
12
13type DaneGatunku = {
14 nazwa: string;
15 grupaTaksonomiczna: GrupaTaksonomiczna;
16 dieta: KlasaDiety;
17 eraGeologiczna: string;
18 średniaWaga: number;
19 średniaDługość: number;
20 średniWiek: number;
21 zagrożenie: PoziomDostępu;
22 opis: string;
23};
24
25type Okaz = {
26 id: ID;
27 gatunek: string;
28 imię: string;
29 wiek: number;
30 waga: number;
31 płeć: "samiec" | "samica";
32 status: StatusZdrowia;
33 lokalizacja: ID;
34 dataPrzybycia: Date;
35 historia: HistoriaMedyczna[];
36};
37
38type HistoriaMedyczna = {
39 data: Date;
40 typ: "badanie" | "leczenie" | "szczepienie" | "operacja";
41 opis: string;
42 weterynarz: ID;
43};
44
45// Typy pracowników
46type Stanowisko =
47 | "dyrektor"
48 | "badacz"
49 | "weterynarz"
50 | "treser"
51 | "bezpieczeństwo"
52 | "obsługa"
53 | "technik"
54 | "przewodnik";
55
56type Pracownik = {
57 id: ID;
58 imię: string;
59 nazwisko: string;
60 stanowisko: Stanowisko;
61 poziomDostępu: PoziomDostępu;
62 dataPrzyjęcia: Date;
63 kontakt: {
64 telefon: string;
65 email: string;
66 adres?: string;
67 };
68 obszarySpecjalizacji?: string[];
69};
70
71// Typy lokalizacji
72type TypLokalizacji =
73 | "wybieg"
74 | "laboratorium"
75 | "centrum operacyjne"
76 | "strefa publiczna"
77 | "gastronomia"
78 | "sklep"
79 | "atrakcja";
80
81type SystemyBezpieczeństwa = {
82 ogrodzenie: boolean;
83 monitoringWideo: boolean;
84 czujnikiRuchu: boolean;
85 zasilanieZapasowe: boolean;
86 napięcieElektryczne?: number; // tylko dla wybiegów drapieżników
87};
88
89type Lokalizacja = {
90 id: ID;
91 nazwa: string;
92 typ: TypLokalizacji;
93 współrzędne: Koordynaty;
94 powierzchnia: number; // w hektarach
95 pojemność: number; // maksymalna liczba osób/okazów
96 wymaganyPoziomDostępu: PoziomDostępu;
97 status: StatusAktywności;
98 systemyBezpieczeństwa: SystemyBezpieczeństwa;
99};
100
101// Typy zdarzeń
102type TypZdarzenia =
103 | "ucieczkaDinozaura"
104 | "awariaSystemu"
105 | "wypadek"
106 | "choroba"
107 | "urodzenie"
108 | "śmierć"
109 | "transferOkazu"
110 | "zagrożeniePogodowe";
111
112type Zdarzenie = {
113 id: ID;
114 typ: TypZdarzenia;
115 data: Date;
116 lokalizacja: ID;
117 uczestnicyDinozaury?: ID[];
118 uczestnicyPracownicy?: ID[];
119 opis: string;
120 status: "w toku" | "rozwiązane" | "zamknięte";
121 priorytet: 1 | 2 | 3 | 4 | 5;
122 działaniaZapobiegawcze?: string[];
123};
124
125// System zarządzania parkiem
126type SystemZarządzania = {
127 dinozaury: Record<ID, Okaz>;
128 gatunki: Record<string, DaneGatunku>;
129 pracownicy: Record<ID, Pracownik>;
130 lokalizacje: Record<ID, Lokalizacja>;
131 zdarzenia: Record<ID, Zdarzenie>;
132
133 // Metody systemu
134 dodajOkaz: (okaz: Omit<Okaz, "id">) => ID;
135 aktualizujStatusOkazu: (id: ID, status: StatusZdrowia) => void;
136 przeniośOkaz: (id: ID, nowaLokalizacja: ID) => boolean;
137 znajdźOkazy: (filtry: Partial<Okaz>) => Okaz[];
138 generujRaportStanu: () => RaportStanu;
139};
140
141type RaportStanu = {
142 liczbaOkazów: number;
143 rozłożenieGatunków: Record<string, number>;
144 statusyZdrowia: Record<StatusZdrowia, number>;
145 obłożenieLokalizacji: Record<ID, { pojemność: number; aktualna: number }>;
146 ostatnieZdarzenia: Zdarzenie[];
147 alerty: string[];
148};
149
150// Symulacja części systemu
151const systemParkuJurajskiego: Partial<SystemZarządzania> = {
152 dinozaury: {},
153 gatunki: {
154 "Tyrannosaurus": {
155 nazwa: "Tyrannosaurus Rex",
156 grupaTaksonomiczna: "teropody",
157 dieta: "mięsożerca",
158 eraGeologiczna: "późna kreda",
159 średniaWaga: 7000,
160 średniaDługość: 12,
161 średniWiek: 30,
162 zagrożenie: 5,
163 opis: "Jeden z największych drapieżników, jaki kiedykolwiek chodził po Ziemi."
164 },
165 "Velociraptor": {
166 nazwa: "Velociraptor",
167 grupaTaksonomiczna: "teropody",
168 dieta: "mięsożerca",
169 eraGeologiczna: "późna kreda",
170 średniaWaga: 15,
171 średniaDługość: 1.8,
172 średniWiek: 25,
173 zagrożenie: 4,
174 opis: "Mały, szybki i inteligentny drapieżnik, polujący w grupach."
175 }
176 },
177 lokalizacje: {
178 "LOC-001": {
179 id: "LOC-001",
180 nazwa: "Padok T-Rex",
181 typ: "wybieg",
182 współrzędne: [20.1234, -75.8765],
183 powierzchnia: 8,
184 pojemność: 2,
185 wymaganyPoziomDostępu: 4,
186 status: "aktywny",
187 systemyBezpieczeństwa: {
188 ogrodzenie: true,
189 monitoringWideo: true,
190 czujnikiRuchu: true,
191 zasilanieZapasowe: true,
192 napięcieElektryczne: 10000
193 }
194 }
195 }
196};
197
198// Funkcja demonstrująca użycie typów
199function demonstrujSystemZarządzania() {
200 console.log("System zarządzania Parkiem Jurajskim");
201 console.log("----------------------------------");
202
203 console.log("Dostępne gatunki:");
204 Object.values(systemParkuJurajskiego.gatunki || {}).forEach(gatunek => {
205 console.log(`- ${gatunek.nazwa} (${gatunek.dieta}, zagrożenie: ${gatunek.zagrożenie})`);
206 });
207
208 console.log("\nDostępne lokalizacje:");
209 Object.values(systemParkuJurajskiego.lokalizacje || {}).forEach(lok => {
210 console.log(`- ${lok.nazwa} (typ: ${lok.typ}, status: ${lok.status}, dostęp: poziom ${lok.wymaganyPoziomDostępu})`);
211 });
212}
213
214demonstrujSystemZarządzania();Podsumowanie
Aliasy typów w TypeScript są potężnym mechanizmem, który pozwala na tworzenie bardziej czytelnego, utrzymywalnego i bezpiecznego kodu. W kontekście zarządzania złożonym systemem, takim jak Park Jurajski, aliasy typów pozwalają na dokładne modelowanie danych i relacji między nimi.
| Cecha aliasów typów | Zastosowanie w Parku Jurajskim |
|---|---|
| Podstawowe aliasy | Typy identyfikatorów, poziomów bezpieczeństwa |
| Aliasy złożonych typów | Struktury danych dinozaurów, pracowników, lokalizacji |
| Generyczne aliasy | System monitoringu różnych parametrów |
| Rekursywne typy | Hierarchie gatunków, struktura organizacyjna |
| Discriminated unions | Różne poziomy danych, rodzaje zdarzeń |
| Utility types | Zarządzanie modyfikowalnością i dostępnością danych |
Dr. Wu podsumowuje: "Aliasy typów są jak nasze listy kontrolne i protokoły w laboratorium - pozwalają nam jasno określić, jak powinny wyglądać dane i operacje, jednocześnie czyniąc cały system bardziej zrozumiałym. W projekcie tak złożonym jak Park Jurajski, gdzie najmniejszy błąd może prowadzić do katastrofalnych konsekwencji, takie precyzyjne narzędzia są nieocenione."
Kod do tej lekcji: index.ts
1// Type Aliases w Parku Jurajskim
2console.log("Type Aliases TypeScript\n");
3
4// ===========================================
5// 1. Podstawowe type aliases
6// ===========================================
7console.log("=== PODSTAWOWE TYPE ALIASES ===");
8
9// Alias dla prostych typów
10type DinosaurID = string | number;
11type Weight = number;
12type Species = string;
13
14let id1: DinosaurID = "DINO-001";
15let id2: DinosaurID = 123;
16let weight: Weight = 8000;
17let species: Species = "Tyrannosaurus Rex";
18
19console.log("ID:", id1, id2);
20console.log("Weight:", weight);
21console.log("Species:", species);
22
23// ===========================================
24// 2. Type vs Interface
25// ===========================================
26console.log("\n=== TYPE VS INTERFACE ===");
27
28// Type alias
29type DinosaurType = {
30 name: string;
31 species: string;
32 age: number;
33};
34
35// Interface
36interface DinosaurInterface {
37 name: string;
38 species: string;
39 age: number;
40}
41
42const dino1: DinosaurType = {
43 name: "Rex",
44 species: "T-Rex",
45 age: 5
46};
47
48const dino2: DinosaurInterface = {
49 name: "Blue",
50 species: "Velociraptor",
51 age: 3
52};
53
54console.log("Type:", dino1);
55console.log("Interface:", dino2);
56
57// ===========================================
58// 3. Union types z aliases
59// ===========================================
60console.log("\n=== UNION TYPES ===");
61
62type Diet = "carnivore" | "herbivore" | "omnivore";
63type Period = "Triassic" | "Jurassic" | "Cretaceous";
64type SecurityLevel = "low" | "medium" | "high" | "critical";
65
66type Dinosaur = {
67 name: string;
68 diet: Diet;
69 period: Period;
70 dangerLevel: SecurityLevel;
71};
72
73const trex: Dinosaur = {
74 name: "Tyrannosaurus Rex",
75 diet: "carnivore",
76 period: "Cretaceous",
77 dangerLevel: "critical"
78};
79
80console.log("T-Rex:", trex);
81
82// ===========================================
83// 4. Intersection types z aliases
84// ===========================================
85console.log("\n=== INTERSECTION TYPES ===");
86
87type HasName = {
88 name: string;
89};
90
91type HasWeight = {
92 weight: number;
93};
94
95type HasDiet = {
96 diet: Diet;
97};
98
99// Łączenie typów
100type CompleteDinosaur = HasName & HasWeight & HasDiet & {
101 species: string;
102};
103
104const velociraptor: CompleteDinosaur = {
105 name: "Blue",
106 weight: 350,
107 diet: "carnivore",
108 species: "Velociraptor"
109};
110
111console.log("Complete dinosaur:", velociraptor);
112
113// ===========================================
114// 5. Function types
115// ===========================================
116console.log("\n=== FUNCTION TYPES ===");
117
118// Typ funkcji
119type DinosaurFilter = (dino: Dinosaur) => boolean;
120type DinosaurTransformer = (dino: Dinosaur) => string;
121type DinosaurComparator = (a: Dinosaur, b: Dinosaur) => number;
122
123const carnivoreFilter: DinosaurFilter = (dino) => dino.diet === "carnivore";
124const nameTransformer: DinosaurTransformer = (dino) => `${dino.name}`;
125const dangerComparator: DinosaurComparator = (a, b) => {
126 const levels = { low: 1, medium: 2, high: 3, critical: 4 };
127 return levels[b.dangerLevel] - levels[a.dangerLevel];
128};
129
130console.log("Is carnivore:", carnivoreFilter(trex));
131console.log("Transformed:", nameTransformer(trex));
132
133// ===========================================
134// 6. Tuple types
135// ===========================================
136console.log("\n=== TUPLE TYPES ===");
137
138type Coordinates = [latitude: number, longitude: number];
139type DinosaurData = [name: string, weight: number, isCarnivore: boolean];
140type RGB = [red: number, green: number, blue: number];
141
142const paddockLocation: Coordinates = [22.3964, -159.5261];
143const dinoInfo: DinosaurData = ["Rexy", 8000, true];
144const warningColor: RGB = [255, 0, 0];
145
146console.log("Location:", paddockLocation);
147console.log("Dino info:", dinoInfo);
148console.log("Warning color:", warningColor);
149
150// ===========================================
151// 7. Mapped types z aliases
152// ===========================================
153console.log("\n=== MAPPED TYPES ===");
154
155type DinosaurStats = {
156 health: number;
157 hunger: number;
158 energy: number;
159 happiness: number;
160};
161
162// Wszystkie pola jako readonly
163type ReadonlyStats = {
164 readonly [K in keyof DinosaurStats]: DinosaurStats[K];
165};
166
167// Wszystkie pola jako opcjonalne
168type PartialStats = {
169 [K in keyof DinosaurStats]?: DinosaurStats[K];
170};
171
172const stats: DinosaurStats = {
173 health: 100,
174 hunger: 50,
175 energy: 80,
176 happiness: 90
177};
178
179const readonlyStats: ReadonlyStats = stats;
180// readonlyStats.health = 90; // Error
181
182const partialStats: PartialStats = {
183 health: 100,
184 energy: 80
185 // pozostałe pola opcjonalne
186};
187
188console.log("Stats:", stats);
189console.log("Partial stats:", partialStats);
190
191// ===========================================
192// 8. Conditional types
193// ===========================================
194console.log("\n=== CONDITIONAL TYPES ===");
195
196// Conditional type
197type IsCarnivore<T> = T extends { diet: "carnivore" } ? true : false;
198
199type TRexIsCarnivore = IsCarnivore<typeof trex>; // true
200type VelociraptorIsCarnivore = IsCarnivore<typeof velociraptor>; // true
201
202// Extract - wyodrębnia typy spełniające warunek
203type DinosaurSize = "small" | "medium" | "large" | "extra-large";
204type LargeSizes = Extract<DinosaurSize, "large" | "extra-large">;
205
206// Exclude - usuwa typy spełniające warunek
207type SmallMediumSizes = Exclude<DinosaurSize, "large" | "extra-large">;
208
209console.log("Conditional types defined");
210
211// ===========================================
212// 9. Utility types z aliases
213// ===========================================
214console.log("\n=== UTILITY TYPES ===");
215
216type BaseDinosaur = {
217 id: string;
218 name: string;
219 species: string;
220 weight: number;
221};
222
223// Partial - wszystkie pola opcjonalne
224type PartialDinosaur = Partial<BaseDinosaur>;
225
226// Required - wszystkie pola wymagane
227type RequiredDinosaur = Required<BaseDinosaur>;
228
229// Pick - wybierz określone pola
230type DinosaurSummary = Pick<BaseDinosaur, "name" | "species">;
231
232// Omit - usuń określone pola
233type PublicDinosaur = Omit<BaseDinosaur, "id">;
234
235// Record - mapowanie kluczy do typu
236type DinosaurCollection = Record<string, BaseDinosaur>;
237
238const partialDino: PartialDinosaur = {
239 name: "Rex"
240 // wszystkie inne pola opcjonalne
241};
242
243const summary: DinosaurSummary = {
244 name: "Rexy",
245 species: "T-Rex"
246};
247
248const collection: DinosaurCollection = {
249 "t-rex": {
250 id: "001",
251 name: "Rexy",
252 species: "T-Rex",
253 weight: 8000
254 },
255 "velociraptor": {
256 id: "002",
257 name: "Blue",
258 species: "Velociraptor",
259 weight: 350
260 }
261};
262
263console.log("Partial:", partialDino);
264console.log("Summary:", summary);
265console.log("Collection:", collection);
266
267// ===========================================
268// 10. Podsumowanie
269// ===========================================
270console.log("\n=== PODSUMOWANIE ===");
271console.log("Type Aliases - nazwy dla typów");
272console.log("Union & Intersection - łączenie typów");
273console.log("Function Types - typy funkcji");
274console.log("Tuple Types - krotki");
275console.log("Mapped Types - transformacja typów");
276console.log("Conditional Types - warunkowe typy");
277console.log("Utility Types - wbudowane narzędzia");
278
279console.log("\nType Aliases 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. Co to jest type alias w TypeScript?
2. Co to jest type guard w TypeScript?
To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Edytor kodu
Stwórz type alias DinoStatus i funkcję z type guard sprawdzającą czy dinozaur jest mięsożerny.
- Klikanie w kolejności
Ułóż elementy type assertion w TypeScript:
- Układanie w pionie
Uporządkuj metody sprawdzania typów w TypeScript od najprostszych do najbardziej zaawansowanych: