We use cookies to enhance your experience on the site
CodeWorlds

Complex types (array, tuple, enum)

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

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

Go to CodeWorlds