Cours JavaScript et TypeScript · Module 6: Bases de TypeScript
Les types complexes (array, tuple, enum)
Dans cette leçon7
Bienvenue de nouveau au Jurassic Park ! Après avoir fait connaissance avec les types de données de base en TypeScript, nous sommes prêts à passer à des structures plus avancées. Dans la leçon d'aujourd'hui, le Dr Wu nous emmènera au laboratoire, où nous expérimenterons des types de données plus complexes.
Tout comme au Jurassic Park il ne suffit pas de connaître les espèces individuelles - il faut comprendre le fonctionnement d'écosystèmes entiers et des hiérarchies de dinosaures -, en TypeScript il ne suffit pas de connaître uniquement les types de base. Nous devons apprendre à organiser les données en structures plus complexes.
Les types tableau (Array)
Les tableaux en TypeScript sont comme les enclos du Jurassic Park : ils servent à stocker des collections d'éléments similaires. Nous pouvons définir le type d'un tableau de deux façons :
1// Définition d'un tableau de dinosaures
2let dinosaurs: string[] = ["Tyrannosaurus", "Velociraptor", "Triceratops"];
3
4// Notation alternative
5let dinosaursAlt: Array<string> = ["Brachiosaurus", "Stegosaurus", "Ankylosaurus"];
6
7// Tableau de nombres - ex. poids des dinosaures en kilogrammes
8let weights: number[] = [7500, 350, 8500, 35000, 5500];
9
10// Accès aux éléments du tableau
11console.log(`First dinosaur: ${dinosaurs[0]}`); // Tyrannosaurus
12console.log(`Number of dinosaurs: ${dinosaurs.length}`); // 3
13
14// Ajout au tableau
15dinosaurs.push("Spinosaurus");
16console.log(`Now we have ${dinosaurs.length} dinosaurs`); // 4
17
18// Itération sur le tableau
19dinosaurs.forEach(dino => {
20 console.log(`Studying behavior: ${dino}`);
21});Les tableaux peuvent aussi stocker des objets plus complexes :
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// Filtrage du tableau - trouver tous les prédateurs
18const predators = specimenCollection.filter(dino => dino.isPredator);
19console.log(`Number of predators: ${predators.length}`); // 2
20
21// Transformation du tableau - récupérer uniquement les noms des dinosaures
22const dinosaurNames = specimenCollection.map(dino => dino.name);
23console.log(`Specimen names: ${dinosaurNames.join(", ")}`); // "Rex, Blue, Trixie"Les tableaux multidimensionnels
Les tableaux multidimensionnels peuvent servir à représenter des données plus complexes, comme une carte des enclos du Jurassic Park :
1// Tableau à deux dimensions représentant la carte du Jurassic Park
2// 0 = terrain inaccessible, 1 = chemin, 2 = enclos d'herbivores, 3 = enclos de prédateurs
3const jurassicParkMap: 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// Vérifier ce qui se trouve à une position donnée
12function checkTerrain(x: number, y: number): string {
13 const terrain = jurassicParkMap[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!"Les tableaux avec des éléments de types différents - le Tuple
Les tuples sont un type particulier de tableau où nous connaissons le nombre exact d'éléments et leurs types. C'est comme le transport des dinosaures : le type de véhicule et les mesures de sécurité particulières adaptées à chaque espèce doivent être strictement définis.
1// Tuple représentant les données d'un employé : [id, nom, poste, niveau d'accès]
2type ParkEmployee = [number, string, string, number];
3
4const employees: ParkEmployee[] = [
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 avec des éléments de types différents
12// Format : [code ADN, espèce, âge en millions d'années, est un prédateur]
13type GeneticCode = [string, string, number, boolean];
14
15const trexCode: GeneticCode = ["ACGTTCAGC", "Tyrannosaurus Rex", 68, true];
16
17// Déstructuration du tuple
18const [dnaCode, species, age, predator] = trexCode;
19console.log(`DNA: ${dnaCode}, Species: ${species}`);
20
21// Éléments de tuple optionnels (depuis TypeScript 3.0)
22// Format : [id, nom, puce RFID optionnelle]
23type MuseumSpecimen = [number, string, string?];
24
25const dinosaurSpecimen: MuseumSpecimen = [42, "Velociraptor Skull"];
26const specimenWithTag: MuseumSpecimen = [43, "Dinosaur Egg", "RFID-J-43"];Les types énumération (Enum)
Les types énumération (Enum) en TypeScript sont comme les catégories de sécurité du Jurassic Park : ils aident à définir un ensemble de constantes nommées qui peuvent être utilisées dans le code.
1// Définition d'un type énumération pour les catégories de menace
2enum ThreatCategory {
3 Low, // 0
4 Moderate, // 1
5 High, // 2
6 Critical, // 3
7 RedLevel // 4
8}
9
10// Utilisation de l'enum
11let tRexEnclosureThreat: ThreatCategory = ThreatCategory.High;
12
13if (tRexEnclosureThreat >= ThreatCategory.High) {
14 console.log("Double electric fencing recommended!");
15}
16
17// Accès par valeur
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 avec des valeurs spécifiées
32enum DinosaurStatus {
33 Inactive = 0,
34 LimitedActivity = 5,
35 Active = 10,
36 VeryActive = 15,
37 InterventionRequired = 20
38}
39
40let statusRexT: DinosaurStatus = DinosaurStatus.VeryActive;
41console.log(`T-Rex activity level: ${statusRexT}`); // 15
42
43// Enum de chaînes de caractères
44enum DinosaurSpecies {
45 TRex = "Tyrannosaurus Rex",
46 Raptor = "Velociraptor",
47 Tric = "Triceratops",
48 Stego = "Stegosaurus",
49 Brach = "Brachiosaurus"
50}
51
52let publicFavorite: DinosaurSpecies = DinosaurSpecies.TRex;
53console.log(`Today's attraction: ${publicFavorite}`); // "Tyrannosaurus Rex"Const Enum
Le Const Enum est une optimisation de TypeScript qui élimine l'objet enum au moment de la compilation, en remplaçant directement les références à l'enum par leurs valeurs.
1// Définition d'un Const Enum
2const enum SecurityZone {
3 Public = 1,
4 Staff = 2,
5 RestrictedAccess = 3,
6 Laboratories = 4,
7 Danger = 5
8}
9
10// Utilisation du Const Enum
11function checkPermissions(accessLevel: number, requiredZone: SecurityZone): boolean {
12 return accessLevel >= requiredZone;
13}
14
15// Appel avec des valeurs d'enum
16const drWuAccess = checkPermissions(5, SecurityZone.Laboratories); // true
17const staffAccess = checkPermissions(2, SecurityZone.Danger); // falseApplication pratique des types complexes
Voyons comment nous pouvons utiliser ces types complexes pour construire un système de gestion du Jurassic Park :
1// Définition des interfaces et des 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 [systolique, diastolique]
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[]; // Niveau d'activité par tranches de 3 heures (8 valeurs pour une journée complète)
33}
34
35// Création d'un système de gestion des dinosaures
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 // Renvoie un tuple [nom, id, statut] pour chaque dinosaure
81 return this.dinosaurs.map(d => [d.name, d.id, d.status]);
82 }
83}
84
85// Exemple d'utilisation
86const systemJP = new DinosaurManagementSystem();
87
88// Ajout de dinosaures au système
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// Utilisation du système
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// Exemple de rapport quotidien (tableau de 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// Exemple de mise à jour du statut
155systemJP.updateHealthStatus(1, HealthStatus.NeedsAttention);Résumé des types complexes
| Type | Utilisation au Jurassic Park | Exemple |
|---|---|---|
| Array | Collections d'éléments similaires, ex. liste de dinosaures | string[], Dinosaur[] |
| Array multidimensionnel | Représentation spatiale, ex. carte du parc | number[][] |
| Tuple | Structures fixes avec types et tailles définis, ex. données génétiques | [string, string, number, boolean] |
| Enum | Catégories définies, ex. niveaux de menace | enum ThreatCategory {...} |
| Const Enum | Enums optimisés pour la performance | const enum SecurityZone {...} |
N'oublie pas que choisir les bons types de données dans un projet, c'est comme concevoir des enclos sûrs et efficaces au Jurassic Park : une bonne conception dès le départ évite bien des problèmes à l'avenir !
Le Dr Wu le dit toujours : « Le contrôle précis des types est la clé du succès, aussi bien au laboratoire de génétique que dans le code TypeScript. »
Code de cette leçon : index.ts
1// Complex types in Jurassic Park
2console.log("TypeScript complex types\n");
3
4// ===========================================
5// 1. ARRAY - tableaux
6// ===========================================
7console.log("=== TABLEAUX (ARRAY) ===");
8
9// Deux façons de définir des tableaux
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// Opérations sur les tableaux
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=== TUPLE ===");
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 avec des elements nommés (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 avec des elements optionnels
66type PaddockData = [id: string, capacity: number, isLocked?: boolean];
67let paddock1: PaddockData = ["P-01", 5, true];
68let paddock2: PaddockData = ["P-02", 10]; // isLocked optionnel
69
70console.log("Paddock 1:", paddock1);
71console.log("Paddock 2:", paddock2);
72
73// ===========================================
74// 3. ENUM - énumérations
75// ===========================================
76console.log("\n=== ENUM - ÉNUMÉRATIONS ===");
77
78// Enum numérique
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// Enum textuel
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 avec des calculs
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 (optimisation)
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// Function pour les tableaux
127function getTotalWeight(dinosaurs: Dinosaur[]): number {
128 return weights.reduce((sum, w) => sum + w, 0);
129}
130
131console.log("Total weight:", getTotalWeight(collection));
132
133// Function pour les tuple
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// Function pour les enum
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. Résumé
188// ===========================================
189console.log("\n=== RÉSUMÉ ===");
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!");Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Qu’est-ce qu’un tuple en TypeScript ?
Tâches pratiques dans le jeu
- Éditeur de code
Définis un tableau species (string[]) et un tuple [string, number] pour le nom et le poids du dinosaure.
- Tri vertical
Ordonne les types TypeScript du plus général au plus spécifique :
- Tri horizontal
Ordonne les éléments d’une déclaration de tuple en TypeScript :