JavaScript and TypeScript course Β· Module 6: TypeScript Basics
Complex types (array, tuple, enum)
In this lesson7
Welcome back to Jurassic Park! After getting to know the basic data types in TypeScript, we're ready to move on to more advanced structures. In today's lesson Dr. Wu will take us to the laboratory, where we'll experiment with more complex data types.
Just as in Jurassic Park it's not enough to know individual species - you need to understand how entire ecosystems and dinosaur hierarchies work - so in TypeScript it's not enough to know only the basic types. We need to learn how to organize data into more complex structures.
Array types (Array)
Arrays in TypeScript are like enclosures in Jurassic Park - they serve to store collections of similar elements. We can define the type of an array in two ways:
1// Defining an array of dinosaurs
2let dinosaury: string[] = ["Tyrannosaurus", "Velociraptor", "Triceratops"];
3
4// Alternative notation
5let dinosauryAlt: Array<string> = ["Brachiosaurus", "Stegosaurus", "Ankylosaurus"];
6
7// Array of numbers - e.g. dinosaur weights in kilograms
8let wagi: number[] = [7500, 350, 8500, 35000, 5500];
9
10// Accessing array elements
11console.log(`First dinosaur: ${dinosaury[0]}`); // Tyrannosaurus
12console.log(`Number of dinosaurs: ${dinosaury.length}`); // 3
13
14// Adding to the array
15dinosaury.push("Spinosaurus");
16console.log(`Now we have ${dinosaury.length} dinosaurs`); // 4
17
18// Iterating over the array
19dinosaury.forEach(dino => {
20 console.log(`Studying behavior: ${dino}`);
21});Arrays can also store more complex objects:
1// Defining an interface for a dinosaur object
2interface Dinosaur {
3 id: number;
4 name: string;
5 species: string;
6 isPredator: boolean;
7 ageMillionYears: number;
8}
9
10// Array of dinosaur objects
11const specimenCollection: Dinosaur[] = [
12 { id: 1, name: "Rex", species: "Tyrannosaurus", isPredator: true, ageMillionYears: 68 },
13 { id: 2, name: "Blue", species: "Velociraptor", isPredator: true, ageMillionYears: 75 },
14 { id: 3, name: "Trixie", species: "Triceratops", isPredator: false, ageMillionYears: 68 }
15];
16
17// Filtering the array - find all predators
18const predators = specimenCollection.filter(dino => dino.isPredator);
19console.log(`Number of predators: ${predators.length}`); // 2
20
21// Transforming the array - get only dinosaur names
22const dinosaurNames = specimenCollection.map(dino => dino.name);
23console.log(`Specimen names: ${dinosaurNames.join(", ")}`); // "Rex, Blue, Trixie"Multidimensional arrays
Multidimensional arrays can be used to represent more complex data, such as a map of enclosures in Jurassic Park:
1// Two-dimensional array representing the Jurassic Park map
2// 0 = inaccessible terrain, 1 = path, 2 = herbivore enclosure, 3 = predator enclosure
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// Checking what is at a given position
12function checkTerrain(x: number, y: number): string {
13 const terrain = mapaParkuJurajskiego[y][x];
14 switch (terrain) {
15 case 0: return "Inaccessible terrain";
16 case 1: return "Visitor path";
17 case 2: return "Herbivore enclosure";
18 case 3: return "WARNING! Predator enclosure!";
19 default: return "Unknown terrain";
20 }
21}
22
23console.log(checkTerrain(2, 2)); // "WARNING! Predator enclosure!"Arrays with different element types - Tuple
Tuples are a special kind of array where we know the exact number of elements and their types. It's like transporting dinosaurs - the type of vehicle and the special safety measures appropriate for each species must be strictly defined.
1// Tuple representing employee data: [id, name, position, access level]
2type PracownikParku = [number, string, string, number];
3
4const pracownicy: PracownikParku[] = [
5 [1, "John Hammond", "Director", 5],
6 [2, "Dr. Alan Grant", "Paleontologist", 4],
7 [3, "Dr. Ellie Sattler", "Paleobotanist", 4],
8 [4, "Dennis Nedry", "Programmer", 3]
9];
10
11// Tuple with different element types
12// Format: [DNA code, species, age in millions of years, is predator]
13type KodGenetyczny = [string, string, number, boolean];
14
15const kodTRex: KodGenetyczny = ["ACGTTCAGC", "Tyrannosaurus Rex", 68, true];
16
17// Tuple destructuring
18const [dnaCode, species, age, predator] = kodTRex;
19console.log(`DNA: ${dnaCode}, Species: ${species}`);
20
21// Optional tuple elements (from TypeScript 3.0)
22// Format: [id, name, optional RFID tag]
23type OkazMuzealny = [number, string, string?];
24
25const okazDinosaura: OkazMuzealny = [42, "Velociraptor Skull"];
26const okazZTagiem: OkazMuzealny = [43, "Dinosaur Egg", "RFID-J-43"];Enumeration types (Enum)
Enumeration types (Enum) in TypeScript are like safety categories in Jurassic Park - they help define a set of named constants that can be used in code.
1// Defining an enumeration type for threat categories
2enum ThreatCategory {
3 Low, // 0
4 Moderate, // 1
5 High, // 2
6 Critical, // 3
7 RedLevel // 4
8}
9
10// Using the enum
11let tRexEnclosureThreat: ThreatCategory = ThreatCategory.High;
12
13if (tRexEnclosureThreat >= ThreatCategory.High) {
14 console.log("Double electric fencing recommended!");
15}
16
17// Accessing by value
18const categoryDescription = (level: ThreatCategory): string => {
19 switch (level) {
20 case ThreatCategory.Low: return "Standard precautions";
21 case ThreatCategory.Moderate: return "Increased vigilance";
22 case ThreatCategory.High: return "Double security";
23 case ThreatCategory.Critical: return "No visitor access";
24 case ThreatCategory.RedLevel: return "Park evacuation!";
25 default: return "Unknown threat level";
26 }
27};
28
29console.log(categoryDescription(tRexEnclosureThreat)); // "Double security"
30
31// Enum with specified values
32enum DinosaurStatus {
33 Inactive = 0,
34 LimitedActivity = 5,
35 Active = 10,
36 VeryActive = 15,
37 InterventionRequired = 20
38}
39
40let statusRexT: StatusDinosaura = StatusDinosaura.BardzoAktywny;
41console.log(`T-Rex activity level: ${statusRexT}`); // 15
42
43// String enum
44enum GatunekDinosaura {
45 TRex = "Tyrannosaurus Rex",
46 Raptor = "Velociraptor",
47 Tric = "Triceratops",
48 Stego = "Stegosaurus",
49 Brach = "Brachiosaurus"
50}
51
52let publicFavorite: GatunekDinosaura = GatunekDinosaura.TRex;
53console.log(`Today's attraction: ${publicFavorite}`); // "Tyrannosaurus Rex"Const Enum
Const Enum is a TypeScript optimization that eliminates the enum object at compile time, replacing enum references directly with values.
1// Defining a Const Enum
2const enum SecurityZone {
3 Public = 1,
4 Staff = 2,
5 RestrictedAccess = 3,
6 Laboratories = 4,
7 Danger = 5
8}
9
10// Using the Const Enum
11function checkPermissions(accessLevel: number, requiredZone: SecurityZone): boolean {
12 return accessLevel >= requiredZone;
13}
14
15// Calling with enum values
16const drWuAccess = checkPermissions(5, SecurityZone.Laboratories); // true
17const staffAccess = checkPermissions(2, SecurityZone.Danger); // falsePractical application of complex types
Let's look at how we can use these complex types to build a Jurassic Park management system:
1// Defining interfaces and types
2enum HealthStatus {
3 Excellent = "excellent",
4 Good = "good",
5 NeedsAttention = "needs attention",
6 Sick = "sick",
7 Critical = "critical"
8}
9
10enum DietClassification {
11 Herbivore = "herbivore",
12 Omnivore = "omnivore",
13 Predator = "predator"
14}
15
16interface VitalSigns {
17 temperature: number;
18 heartRate: number;
19 bloodPressure: [number, number]; // Tuple [systolic, diastolic]
20 stressLevel: number; // 1-10
21}
22
23interface Dinosaur {
24 id: number;
25 name: string;
26 species: string;
27 dietClassification: DietClassification;
28 age: number;
29 weight: number;
30 status: HealthStatus;
31 vitalSigns: VitalSigns;
32 dailyActivityArray: number[]; // Activity level in 3-hour periods (8 values for full day)
33}
34
35// Creating a dinosaur management system
36class DinosaurManagementSystem {
37 private dinosaurs: Dinosaur[] = [];
38
39 addDinosaur(dino: Dinosaur): void {
40 this.dinosaurs.push(dino);
41 console.log(`Added dinosaur: ${dino.name} (${dino.species})`);
42 }
43
44 findDinosaur(id: number): Dinosaur | undefined {
45 return this.dinosaurs.find(d => d.id === id);
46 }
47
48 updateHealthStatus(id: number, newStatus: HealthStatus): boolean {
49 const dino = this.findDinosaur(id);
50 if (dino) {
51 dino.status = newStatus;
52 console.log(`Updated health status of ${dino.name} to: ${newStatus}`);
53 return true;
54 }
55 return false;
56 }
57
58 getPredators(): Dinosaur[] {
59 return this.dinosaurs.filter(d => d.dietClassification === DietClassification.Predator);
60 }
61
62 getDinosaursNeedingAttention(): Dinosaur[] {
63 return this.dinosaurs.filter(d =>
64 d.status === HealthStatus.NeedsAttention ||
65 d.status === HealthStatus.Sick ||
66 d.status === HealthStatus.Critical
67 );
68 }
69
70 calculateAverageActivity(id: number): number | null {
71 const dino = this.findDinosaur(id);
72 if (dino) {
73 const sum = dino.dailyActivityArray.reduce((acc, val) => acc + val, 0);
74 return sum / dino.dailyActivityArray.length;
75 }
76 return null;
77 }
78
79 prepareDailyReport(): [string, number, HealthStatus][] {
80 // Returns a tuple [name, id, status] for each dinosaur
81 return this.dinosaurs.map(d => [d.name, d.id, d.status]);
82 }
83}
84
85// Sample usage
86const systemJP = new DinosaurManagementSystem();
87
88// Adding dinosaurs to the system
89systemJP.addDinosaur({
90 id: 1,
91 name: "Rexy",
92 species: "Tyrannosaurus Rex",
93 dietClassification: DietClassification.Predator,
94 age: 7,
95 weight: 8000,
96 status: HealthStatus.Good,
97 vitalSigns: {
98 temperature: 38.2,
99 heartRate: 70,
100 bloodPressure: [140, 90],
101 stressLevel: 3
102 },
103 dailyActivityArray: [2, 1, 0, 0, 1, 3, 5, 2]
104});
105
106systemJP.addDinosaur({
107 id: 2,
108 name: "Blue",
109 species: "Velociraptor",
110 dietClassification: DietClassification.Predator,
111 age: 3,
112 weight: 350,
113 status: HealthStatus.Excellent,
114 vitalSigns: {
115 temperature: 39.1,
116 heartRate: 95,
117 bloodPressure: [130, 85],
118 stressLevel: 2
119 },
120 dailyActivityArray: [4, 2, 1, 0, 2, 5, 6, 3]
121});
122
123systemJP.addDinosaur({
124 id: 3,
125 name: "Spike",
126 species: "Stegosaurus",
127 dietClassification: DietClassification.Herbivore,
128 age: 12,
129 weight: 5000,
130 status: HealthStatus.NeedsAttention,
131 vitalSigns: {
132 temperature: 37.5,
133 heartRate: 50,
134 bloodPressure: [125, 80],
135 stressLevel: 6
136 },
137 dailyActivityArray: [3, 3, 2, 1, 3, 2, 2, 1]
138});
139
140// Using the system
141const predators = systemJP.getPredators();
142console.log(`Number of predators in the park: ${predators.length}`);
143
144const needingAttention = systemJP.getDinosaursNeedingAttention();
145console.log(`Number of dinosaurs needing attention: ${needingAttention.length}`);
146
147// Daily report example (array of tuples)
148const dailyReport = systemJP.prepareDailyReport();
149console.log("\nDaily dinosaur status report:");
150dailyReport.forEach(([name, id, status]) => {
151 console.log(`- ${name} (ID: ${id}): ${status}`);
152});
153
154// Status update example
155systemJP.updateHealthStatus(1, HealthStatus.NeedsAttention);Summary of complex types
| Type | Use in Jurassic Park | Example |
|---|---|---|
| Array | Collections of similar elements, e.g. list of dinosaurs | string[], Dinosaur[] |
| Multidimensional Array | Spatial representation, e.g. park map | number[][] |
| Tuple | Fixed structures with defined types and sizes, e.g. genetic data | [string, string, number, boolean] |
| Enum | Defined categories, e.g. threat levels | enum ThreatCategory {...} |
| Const Enum | Optimized enums for performance | const enum SecurityZone {...} |
Remember that choosing the right data types in a project is like designing safe and efficient enclosures in Jurassic Park - good design at the start saves many problems in the future!
Dr. Wu always says: "Precise control of types is the key to success - both in the genetics laboratory and in TypeScript code."
Code for this lesson: index.ts
1// Complex types in Jurassic Park
2console.log("TypeScript complex types\n");
3
4// ===========================================
5// 1. ARRAY - arrays
6// ===========================================
7console.log("=== ARRAYS ===");
8
9// Two ways to define arrays
10let dinosaurs: string[] = ["Tyrannosaurus", "Velociraptor", "Triceratops"];
11let weights: Array<number> = [7500, 350, 8500, 35000];
12
13console.log("Dinosaurs:", dinosaurs);
14console.log("First dinosaur:", dinosaurs[0]);
15console.log("Count:", dinosaurs.length);
16
17// Array operations
18dinosaurs.push("Spinosaurus");
19console.log("After push:", dinosaurs);
20
21// Iteration
22dinosaurs.forEach((dino, index) => {
23 console.log(`${index + 1}. ${dino}`);
24});
25
26// Array of objects
27interface Dinosaur {
28 id: number;
29 name: string;
30 species: string;
31 isCarnivore: boolean;
32 ageMillionYears: number;
33}
34
35const collection: Dinosaur[] = [
36 { id: 1, name: "Rex", species: "Tyrannosaurus", isCarnivore: true, ageMillionYears: 68 },
37 { id: 2, name: "Blue", species: "Velociraptor", isCarnivore: true, ageMillionYears: 75 },
38 { id: 3, name: "Trike", species: "Triceratops", isCarnivore: false, ageMillionYears: 68 }
39];
40
41console.log("\nDinosaur collection:", collection);
42
43// Filtering
44const carnivores = collection.filter(d => d.isCarnivore);
45console.log("Carnivores:", carnivores.map(d => d.name));
46
47// ===========================================
48// 2. TUPLE - tuples
49// ===========================================
50console.log("\n=== TUPLES ===");
51
52// Tuple - array with fixed length and types
53let dinoData: [string, number, boolean] = ["T-Rex", 8000, true];
54
55console.log("Species:", dinoData[0]);
56console.log("Weight:", dinoData[1]);
57console.log("Is dangerous:", dinoData[2]);
58
59// Tuple with named elements (TS 4.0+)
60type DinoTuple = [species: string, weight: number, dangerous: boolean];
61let velociraptor: DinoTuple = ["Velociraptor", 350, true];
62
63console.log("Velociraptor data:", velociraptor);
64
65// Tuple with optional elements
66type PaddockData = [id: string, capacity: number, isLocked?: boolean];
67let paddock1: PaddockData = ["P-01", 5, true];
68let paddock2: PaddockData = ["P-02", 10]; // isLocked is optional
69
70console.log("Paddock 1:", paddock1);
71console.log("Paddock 2:", paddock2);
72
73// ===========================================
74// 3. ENUM - enumerations
75// ===========================================
76console.log("\n=== ENUM - ENUMERATIONS ===");
77
78// Numeric enum
79enum SecurityLevel {
80 Green = 1,
81 Yellow = 2,
82 Orange = 3,
83 Red = 4,
84 Critical = 5
85}
86
87let currentSecurity: SecurityLevel = SecurityLevel.Orange;
88console.log("Security level:", SecurityLevel[currentSecurity]); // "Orange"
89console.log("Security value:", currentSecurity); // 3
90
91// String enum
92enum DinosaurDiet {
93 Carnivore = "CARNIVORE",
94 Herbivore = "HERBIVORE",
95 Omnivore = "OMNIVORE"
96}
97
98let trexDiet: DinosaurDiet = DinosaurDiet.Carnivore;
99console.log("T-Rex diet:", trexDiet); // "CARNIVORE"
100
101// Enum with calculations
102enum PaddockSize {
103 Small = 100,
104 Medium = 500,
105 Large = 1000,
106 ExtraLarge = Large * 2 // 2000
107}
108
109console.log("Extra large paddock:", PaddockSize.ExtraLarge);
110
111// Const enum (optimization)
112const enum DinosaurPeriod {
113 Triassic = "TRIASSIC",
114 Jurassic = "JURASSIC",
115 Cretaceous = "CRETACEOUS"
116}
117
118let trexPeriod: DinosaurPeriod = DinosaurPeriod.Cretaceous;
119console.log("T-Rex period:", trexPeriod);
120
121// ===========================================
122// 4. Helper functions for complex types
123// ===========================================
124console.log("\n=== OPERATIONS ON COMPLEX TYPES ===");
125
126// A function for arrays
127function getTotalWeight(dinosaurs: Dinosaur[]): number {
128 return weights.reduce((sum, w) => sum + w, 0);
129}
130
131console.log("Total weight:", getTotalWeight(collection));
132
133// A function for tuples
134function createDinoTuple(species: string, weight: number, dangerous: boolean): DinoTuple {
135 return [species, weight, dangerous];
136}
137
138const newDino = createDinoTuple("Stegosaurus", 5000, false);
139console.log("New dinosaur:", newDino);
140
141// A function for enums
142function getSecurityColor(level: SecurityLevel): string {
143 switch (level) {
144 case SecurityLevel.Green:
145 return "Green";
146 case SecurityLevel.Yellow:
147 return "Yellow";
148 case SecurityLevel.Orange:
149 return "Orange";
150 case SecurityLevel.Red:
151 return "Red";
152 case SecurityLevel.Critical:
153 return "Critical";
154 default:
155 return "Unknown";
156 }
157}
158
159console.log("Current security:", getSecurityColor(currentSecurity));
160
161// ===========================================
162// 5. Nested structures
163// ===========================================
164console.log("\n=== NESTED STRUCTURES ===");
165
166interface Paddock {
167 id: string;
168 size: PaddockSize;
169 security: SecurityLevel;
170 dinosaurs: Dinosaur[];
171 coordinates: [latitude: number, longitude: number];
172}
173
174const trexPaddock: Paddock = {
175 id: "P-01",
176 size: PaddockSize.Large,
177 security: SecurityLevel.Critical,
178 dinosaurs: [collection[0]],
179 coordinates: [22.3964, -159.5261]
180};
181
182console.log("T-Rex Paddock:", trexPaddock);
183console.log("Coordinates:", trexPaddock.coordinates);
184console.log("Dinosaurs in paddock:", trexPaddock.dinosaurs.length);
185
186// ===========================================
187// 6. Summary
188// ===========================================
189console.log("\n=== SUMMARY ===");
190console.log("Array - collections of elements of the same type");
191console.log("Tuple - arrays of fixed length and different types");
192console.log("Enum - named constant values");
193console.log("Nesting - combining complex structures");
194
195console.log("\nComplex types mastered!");Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What is a tuple in TypeScript?
Hands-on tasks in the game
- Code editor
Define a species array (string[]) and a tuple [string, number] for the dinosaur name and weight.
- Vertical ordering
Order TypeScript types from most general to most specific:
- Horizontal ordering
Arrange the elements of a tuple declaration in TypeScript: