Cours JavaScript et TypeScript · Module 7: TypeScript avancé
Éviter l'imbrication profonde - les retours anticipés
Dans cette leçon6
Le Dr Ian Malcolm, assis au centre de contrôle de Jurassic Park, observe le code écrit par l'équipe informatique. « Regardez ça », dit-il en pointant l'écran. « C'est comme traverser un labyrinthe rempli de dinosaures - chaque if est un nouveau virage, chaque else est une impasse. Le chaos trouve toujours un chemin... mais nous ne devrions pas rendre le chemin plus difficile ! »
Le problème : l'anti-motif de la flèche
L'un des problèmes les plus courants dans le code des programmeurs débutants est ce qu'on appelle l'« anti-motif de la flèche » ou la « pyramide du destin » - un code qui s'imbrique de plus en plus profondément, créant une forme caractéristique de flèche :
1// BAD: Arrow Anti-Pattern - code nested like a pyramid
2function checkDinosaurSafety(dinosaur) {
3 if (dinosaur) {
4 if (dinosaur.isAlive) {
5 if (dinosaur.enclosure) {
6 if (dinosaur.enclosure.fence) {
7 if (dinosaur.enclosure.fence.isActive) {
8 if (dinosaur.health > 50) {
9 if (dinosaur.aggressionLevel < 7) {
10 if (dinosaur.lastFed) {
11 const hoursSinceFeeding = (Date.now() - dinosaur.lastFed) / 3600000;
12 if (hoursSinceFeeding < 12) {
13 return 'Safe';
14 } else {
15 return 'Hungry - be careful!';
16 }
17 } else {
18 return 'No feeding data';
19 }
20 } else {
21 return 'High aggression level!';
22 }
23 } else {
24 return 'Low health level';
25 }
26 } else {
27 return 'ALARM: Fence inactive!';
28 }
29 } else {
30 return 'ERROR: No fence';
31 }
32 } else {
33 return 'ERROR: No assigned enclosure';
34 }
35 } else {
36 return 'Dinosaur deceased';
37 }
38 } else {
39 return 'No dinosaur data';
40 }
41}
42
43// This code is:
44// - Hard to read (you have to count brackets)
45// - Hard to understand (logic is scattered)
46// - Hard to modify (adding a condition requires reorganization)
47// - Error-prone (easy to get lost in the nesting)La solution : les retours anticipés (clauses de garde)
Plutôt que d'imbriquer le code, nous utilisons des retours anticipés - nous vérifions les conditions d'erreur au début et sortons immédiatement de la fonction. On parle aussi de « clauses de garde » (guard clauses).
1// GOOD: Early Returns - readable linear code
2function checkDinosaurSafety(dinosaur) {
3 // Check all error conditions right away
4 if (!dinosaur) {
5 return 'No dinosaur data';
6 }
7
8 if (!dinosaur.isAlive) {
9 return 'Dinosaur deceased';
10 }
11
12 if (!dinosaur.enclosure) {
13 return 'ERROR: No assigned enclosure';
14 }
15
16 if (!dinosaur.enclosure.fence) {
17 return 'ERROR: No fence';
18 }
19
20 if (!dinosaur.enclosure.fence.isActive) {
21 return 'ALARM: Fence inactive!';
22 }
23
24 if (dinosaur.health <= 50) {
25 return 'Low health level';
26 }
27
28 if (dinosaur.aggressionLevel >= 7) {
29 return 'High aggression level!';
30 }
31
32 if (!dinosaur.lastFed) {
33 return 'No feeding data';
34 }
35
36 // Main logic at the end
37 const hoursSinceFeeding = (Date.now() - dinosaur.lastFed) / 3600000;
38
39 if (hoursSinceFeeding >= 12) {
40 return 'Hungry - be careful!';
41 }
42
43 return 'Safe';
44}
45
46// This code is:
47// Easy to read (linear flow)
48// Easy to understand (each condition is separate)
49// Easy to modify (adding a condition = one line)
50// Less error-prone (no nesting)Règles pour utiliser les retours anticipés
1. Vérifier d'abord les cas limites et les erreurs
1// BAD: Main logic hidden in nesting
2function processVisitorEntry(visitor, ticket) {
3 if (visitor && ticket) {
4 if (ticket.isValid) {
5 if (ticket.hasAdultSupervision || visitor.age >= 18) {
6 if (visitor.hasHealthClearance) {
7 // Main logic deeply nested
8 registerEntry(visitor);
9 return true;
10 }
11 }
12 }
13 }
14 return false;
15}
16
17// GOOD: Edge cases first
18function processVisitorEntry(visitor, ticket) {
19 // Input data validation
20 if (!visitor || !ticket) {
21 throw new Error('Missing visitor or ticket data');
22 }
23
24 // Checking conditions from most basic
25 if (!ticket.isValid) {
26 throw new Error('Invalid ticket');
27 }
28
29 if (visitor.age < 18 && !ticket.hasAdultSupervision) {
30 throw new Error('Minor requires adult supervision');
31 }
32
33 if (!visitor.hasHealthClearance) {
34 throw new Error('No health clearance');
35 }
36
37 // Main logic at the end - now we know everything is OK
38 registerEntry(visitor);
39 return true;
40}2. Utiliser la négation pour les conditions d'erreur
1// BAD: Positive conditions lead to nesting
2function feedDinosaur(dinosaurId, foodAmount) {
3 if (dinosaurs.has(dinosaurId)) {
4 const dino = dinosaurs.get(dinosaurId);
5 if (dino.isAlive) {
6 if (foodAmount > 0) {
7 if (foodAmount <= MAX_FOOD_PORTION) {
8 // Feeding logic
9 dino.feed(foodAmount);
10 return true;
11 }
12 }
13 }
14 }
15 return false;
16}
17
18// GOOD: Negating conditions allows early return
19function feedDinosaur(dinosaurId, foodAmount) {
20 // Check all ERROR conditions and exit immediately
21 if (!dinosaurs.has(dinosaurId)) {
22 throw new Error(`Dinosaur ${dinosaurId} does not exist`);
23 }
24
25 const dino = dinosaurs.get(dinosaurId);
26
27 if (!dino.isAlive) {
28 throw new Error('Cannot feed a dead dinosaur');
29 }
30
31 if (foodAmount <= 0) {
32 throw new Error('Food amount must be greater than 0');
33 }
34
35 if (foodAmount > MAX_FOOD_PORTION) {
36 throw new Error(`Maximum portion is ${MAX_FOOD_PORTION}kg`);
37 }
38
39 // Main logic - we know everything is OK
40 dino.feed(foodAmount);
41 return true;
42}3. Extraire la logique complexe dans des fonctions séparées
1// BAD: Complex logic nested
2function authorizeAccess(employee, sector) {
3 if (employee) {
4 if (employee.isActive) {
5 if (employee.clearanceLevel >= sector.requiredClearance) {
6 if (employee.department === sector.allowedDepartment ||
7 employee.role === 'Admin' ||
8 employee.temporaryAccess.includes(sector.id)) {
9 if (!employee.accessRestrictions.includes(sector.id)) {
10 if (isWithinAllowedHours(employee.schedule, sector.operatingHours)) {
11 return grantAccess(employee, sector);
12 }
13 }
14 }
15 }
16 }
17 }
18 return denyAccess(employee, sector);
19}
20
21// GOOD: Extract conditions into helper functions
22function authorizeAccess(employee, sector) {
23 if (!employee) {
24 return denyAccess(null, sector, 'No employee data');
25 }
26
27 if (!employee.isActive) {
28 return denyAccess(employee, sector, 'Account inactive');
29 }
30
31 if (!hasSufficientClearance(employee, sector)) {
32 return denyAccess(employee, sector, 'Insufficient clearance level');
33 }
34
35 if (!isDepartmentAuthorized(employee, sector)) {
36 return denyAccess(employee, sector, 'Unauthorized department');
37 }
38
39 if (hasAccessRestriction(employee, sector)) {
40 return denyAccess(employee, sector, 'Access restriction');
41 }
42
43 if (!isWithinAllowedHours(employee.schedule, sector.operatingHours)) {
44 return denyAccess(employee, sector, 'Outside allowed hours');
45 }
46
47 return grantAccess(employee, sector);
48}
49
50// Helper functions - each with a single responsibility
51function hasSufficientClearance(employee, sector) {
52 return employee.clearanceLevel >= sector.requiredClearance;
53}
54
55function isDepartmentAuthorized(employee, sector) {
56 return employee.department === sector.allowedDepartment ||
57 employee.role === 'Admin' ||
58 employee.temporaryAccess.includes(sector.id);
59}
60
61function hasAccessRestriction(employee, sector) {
62 return employee.accessRestrictions.includes(sector.id);
63}Exemples pratiques de refactorisation
Exemple 1 : système d'alarme
1// BEFORE: Nested code hard to read
2function triggerAlarm(sensorData) {
3 if (sensorData) {
4 if (sensorData.fence) {
5 if (sensorData.fence.voltage < MIN_VOLTAGE) {
6 if (emergencyProtocol.isActive) {
7 if (securityTeam.isAvailable) {
8 if (evacuationRoutes.areOpen) {
9 activateFullAlarm();
10 notifySecurityTeam();
11 return { status: 'active', level: 'critical' };
12 } else {
13 activatePartialAlarm();
14 return { status: 'active', level: 'warning' };
15 }
16 } else {
17 activateAutomatedResponse();
18 return { status: 'automated', level: 'critical' };
19 }
20 } else {
21 logIncident();
22 return { status: 'logged', level: 'info' };
23 }
24 } else {
25 return { status: 'normall', level: 'info' };
26 }
27 }
28 }
29 return { status: 'error', level: 'critical' };
30}
31
32// AFTER: Readable code with early returns
33function triggerAlarm(sensorData) {
34 // Data validation
35 if (!sensorData || !sensorData.fence) {
36 return { status: 'error', level: 'critical', message: 'No sensor data' };
37 }
38
39 // Check main condition
40 if (sensorData.fence.voltage >= MIN_VOLTAGE) {
41 return { status: 'normall', level: 'info', message: 'Voltage normall' };
42 }
43
44 // Low voltage detected - check protocols
45 if (!emergencyProtocol.isActive) {
46 logIncident();
47 return { status: 'logged', level: 'info', message: 'Incident logged' };
48 }
49
50 // Protocol active - check team availability
51 if (!securityTeam.isAvailable) {
52 activateAutomatedResponse();
53 return { status: 'automated', level: 'critical', message: 'Automated response' };
54 }
55
56 // Team available - check evacuation routes
57 if (!evacuationRoutes.areOpen) {
58 activatePartialAlarm();
59 return { status: 'active', level: 'warning', message: 'Partial alarm' };
60 }
61
62 // Everything ready - full alarm
63 activateFullAlarm();
64 notifySecurityTeam();
65 return { status: 'active', level: 'critical', message: 'Full alarm activated' };
66}Exemple 2 : validation de formulaire
1// BEFORE: Validation with many nesting levels
2function validateVisitorRegistration(formData) {
3 if (formData.firstName) {
4 if (formData.lastName) {
5 if (formData.email) {
6 if (isValidEmail(formData.email)) {
7 if (formData.age) {
8 if (formData.age >= 5 && formData.age <= 120) {
9 if (formData.emergencyContact) {
10 if (formData.emergencyContact.phone) {
11 if (isValidPhone(formData.emergencyContact.phone)) {
12 if (formData.acceptedTerms) {
13 return { valid: true, data: formData };
14 } else {
15 return { valid: false, error: 'You must accept the terms' };
16 }
17 } else {
18 return { valid: false, error: 'Invalid emergency phone number' };
19 }
20 } else {
21 return { valid: false, error: 'Missing emergency phone number' };
22 }
23 } else {
24 return { valid: false, error: 'Missing emergency contact' };
25 }
26 } else {
27 return { valid: false, error: 'Age must be between 5 and 120' };
28 }
29 } else {
30 return { valid: false, error: 'Missing age' };
31 }
32 } else {
33 return { valid: false, error: 'Invalid email address' };
34 }
35 } else {
36 return { valid: false, error: 'Missing email address' };
37 }
38 } else {
39 return { valid: false, error: 'Missing last name' };
40 }
41 } else {
42 return { valid: false, error: 'Missing first name' };
43 }
44}
45
46// AFTER: Readable validation with early returns
47function validateVisitorRegistration(formData) {
48 // Validate required text fields
49 if (!formData.firstName) {
50 return { valid: false, error: 'Missing first name' };
51 }
52
53 if (!formData.lastName) {
54 return { valid: false, error: 'Missing last name' };
55 }
56
57 if (!formData.email) {
58 return { valid: false, error: 'Missing email address' };
59 }
60
61 if (!isValidEmail(formData.email)) {
62 return { valid: false, error: 'Invalid email address' };
63 }
64
65 // Age validation
66 if (!formData.age) {
67 return { valid: false, error: 'Missing age' };
68 }
69
70 if (formData.age < 5 || formData.age > 120) {
71 return { valid: false, error: 'Age must be between 5 and 120' };
72 }
73
74 // Emergency contact validation
75 if (!formData.emergencyContact) {
76 return { valid: false, error: 'Missing emergency contact' };
77 }
78
79 if (!formData.emergencyContact.phone) {
80 return { valid: false, error: 'Missing emergency phone number' };
81 }
82
83 if (!isValidPhone(formData.emergencyContact.phone)) {
84 return { valid: false, error: 'Invalid emergency phone number' };
85 }
86
87 // Terms acceptance validation
88 if (!formData.acceptedTerms) {
89 return { valid: false, error: 'You must accept the terms' };
90 }
91
92 // All validations passed
93 return { valid: true, data: formData };
94}Exemple 3 : traitement de commande
1// BEFORE: Complex business logic in nesting
2function processFoodOrder(order) {
3 if (order && order.items && order.items.length > 0) {
4 if (inventory.checkAvailability(order.items)) {
5 const total = calculateTotal(order.items);
6 if (order.payment) {
7 if (order.payment.amount >= total) {
8 if (order.deliveryLocation) {
9 if (isDeliveryLocationSafe(order.deliveryLocation)) {
10 if (deliveryPersonnel.isAvailable()) {
11 const receipt = generateReceipt(order, total);
12 inventory.reduceStock(order.items);
13 scheduleDelivery(order);
14 return { success: true, receipt };
15 } else {
16 return { success: false, reason: 'No available delivery personnel' };
17 }
18 } else {
19 return { success: false, reason: 'Unsafe delivery location' };
20 }
21 } else {
22 return { success: false, reason: 'Missing delivery location' };
23 }
24 } else {
25 return { success: false, reason: 'Insufficient payment amount' };
26 }
27 } else {
28 return { success: false, reason: 'Missing payment data' };
29 }
30 } else {
31 return { success: false, reason: 'Products unavailable in stock' };
32 }
33 } else {
34 return { success: false, reason: 'Invalid order' };
35 }
36}
37
38// AFTER: Business logic divided into steps
39function processFoodOrder(order) {
40 // Step 1: Order validation
41 const validationError = validateOrder(order);
42 if (validationError) {
43 return { success: false, reason: validationError };
44 }
45
46 // Step 2: Check stock availability
47 if (!inventory.checkAvailability(order.items)) {
48 return { success: false, reason: 'Products unavailable in stock' };
49 }
50
51 // Step 3: Payment verification
52 const total = calculateTotal(order.items);
53 const paymentError = validatePayment(order.payment, total);
54 if (paymentError) {
55 return { success: false, reason: paymentError };
56 }
57
58 // Step 4: Delivery verification
59 const deliveryError = validateDelivery(order.deliveryLocation);
60 if (deliveryError) {
61 return { success: false, reason: deliveryError };
62 }
63
64 if (!deliveryPersonnel.isAvailable()) {
65 return { success: false, reason: 'No available delivery personnel' };
66 }
67
68 // Step 5: Order fulfillment
69 const receipt = generateReceipt(order, total);
70 inventory.reduceStock(order.items);
71 scheduleDelivery(order);
72
73 return { success: true, receipt };
74}
75
76// Helper functions
77function validateOrder(order) {
78 if (!order) return 'Missing order';
79 if (!order.items || order.items.length === 0) return 'No products in order';
80 return null;
81}
82
83function validatePayment(payment, requiredAmount) {
84 if (!payment) return 'Missing payment data';
85 if (payment.amount < requiredAmount) return 'Insufficient payment amount';
86 return null;
87}
88
89function validateDelivery(location) {
90 if (!location) return 'Missing delivery location';
91 if (!isDeliveryLocationSafe(location)) return 'Unsafe delivery location';
92 return null;
93}Techniques supplémentaires
1. Utiliser le chaînage optionnel et la coalescence des nuls
1// BEFORE: Nested null/undefined checking
2function getDinosaurLocation(dinosaurId) {
3 const dino = dinosaurs.get(dinosaurId);
4 if (dino) {
5 if (dino.enclosure) {
6 if (dino.enclosure.location) {
7 return dino.enclosure.location.coordinates;
8 }
9 }
10 }
11 return null;
12}
13
14// AFTER: Optional chaining
15function getDinosaurLocation(dinosaurId) {
16 const dino = dinosaurs.get(dinosaurId);
17 return dino?.enclosure?.location?.coordinates ?? null;
18}2. Extraire les conditions complexes dans des variables
1// BEFORE: Hard to understand condition
2function shouldEvacuate(park) {
3 if ((park.fenceStatus === 'breached' && park.dangerousDinosaurs > 0) ||
4 (park.powerOutage && park.backupGeneratorFailed) ||
5 (park.weatherAlert === 'severe' && park.visitorCount > 100)) {
6 return true;
7 }
8 return false;
9}
10
11// AFTER: Named conditions
12function shouldEvacuate(park) {
13 const hasDangerousBreach = park.fenceStatus === 'breached' && park.dangerousDinosaurs > 0;
14 const hasTotalPowerFailure = park.powerOutage && park.backupGeneratorFailed;
15 const hasWeatherEmergency = park.weatherAlert === 'severe' && park.visitorCount > 100;
16
17 return hasDangerousBreach || hasTotalPowerFailure || hasWeatherEmergency;
18}3. Utiliser le polymorphisme (stratégie) plutôt que switch/if-else
1// BEFORE: Long if-else chain
2function handleDinosaurBehavior(dinosaur, behavior) {
3 if (behavior === 'aggressive') {
4 activateDefenses();
5 alertSecurity();
6 evacuateVisitors();
7 } else if (behavior === 'scared') {
8 reduceNoiseLevel();
9 increaseDistance();
10 } else if (behavior === 'hungry') {
11 prepareFoodration();
12 scheduleFeedingTime();
13 } else if (behavior === 'sleeping') {
14 reduceActivity();
15 dimLights();
16 } else if (behavior === 'playful') {
17 allowInteraction();
18 monitorClosely();
19 } else {
20 logUnknownBehavior(behavior);
21 }
22}
23
24// AFTER: Strategy with a function map
25const behaviorHandlers = {
26 aggressive: () => {
27 activateDefenses();
28 alertSecurity();
29 evacuateVisitors();
30 },
31 scared: () => {
32 reduceNoiseLevel();
33 increaseDistance();
34 },
35 hungry: () => {
36 prepareFoodRation();
37 scheduleFeedingTime();
38 },
39 sleeping: () => {
40 reduceActivity();
41 dimLights();
42 },
43 playful: () => {
44 allowInteraction();
45 monitorClosely();
46 }
47};
48
49function handleDinosaurBehavior(dinosaur, behavior) {
50 const handler = behaviorHandlers[behavior];
51
52 if (!handler) {
53 logUnknownBehavior(behavior);
54 return;
55 }
56
57 handler();
58}Résumé
« La vie... trouve toujours un chemin », dit le Dr Malcolm. « Mais le code ne devrait pas être un labyrinthe. Chaque fonction devrait avoir un chemin clair et linéaire - de la validation au début jusqu'à la logique métier à la fin. »
Principes clés :
- Vérifie d'abord les erreurs - utilise les retours anticipés pour les cas limites
- Inverse les conditions - au lieu de
if (x), utiliseif (!x) return - Évite l'imbrication - maximum 2 à 3 niveaux
- Extrais la logique - conditions complexes -> fonctions auxiliaires
- Nomme les conditions - assigne les expressions complexes à des variables
- Utilise le JS moderne - chaînage optionnel, coalescence des nuls
Un code avec des retours anticipés est :
- Plus lisible - le flux est plus facile à comprendre
- Plus facile à maintenir - on ajoute facilement une nouvelle condition
- Moins sujet aux erreurs - moins d'endroits où les choses peuvent mal tourner
- Plus testable - chaque condition peut être testée séparément
Souviens-toi : un bon code n'est pas seulement un code qui fonctionne - c'est un code facile à comprendre et à modifier. Et à Jurassic Park, où chaque erreur peut avoir des conséquences catastrophiques, la lisibilité du code peut sauver des vies !
Code de cette leçon : index.ts
1// Éviter l'imbrication profonde - Early Returns
2// Jurassic Park : système de sécurité avec clauses de garde
3console.log("=== EARLY RETURNS - PARC JURASSIQUE ===\n");
4
5// ===========================================
6// 1. Exemple : vérification de la sécurité d'un dinosaure
7// ===========================================
8console.log("=== 1. VÉRIFICATION DE LA SÉCURITÉ ===");
9
10interface DinosaurData {
11 name: string;
12 isAlive: boolean;
13 health: number;
14 aggressionLevel: number;
15 enclosure?: {
16 fence?: {
17 isActive: boolean;
18 voltage: number;
19 };
20 };
21 lastFed?: number;
22}
23
24// Retours anticipés - chaque condition vérifiée séparément
25function checkSafety(dino: DinosaurData): string {
26 if (!dino) {
27 return "ERREUR: Aucune donnée sur le dinosaure";
28 }
29
30 if (!dino.isAlive) {
31 return "Dinosaur mort - aucun danger";
32 }
33
34 if (!dino.enclosure?.fence) {
35 return "ALARM: Fence manquante !";
36 }
37
38 if (!dino.enclosure.fence.isActive) {
39 return "ALARM: Fence inactive !";
40 }
41
42 if (dino.health <= 30) {
43 return "AVERTISSEMENT: Niveau de santé bas";
44 }
45
46 if (dino.aggressionLevel >= 8) {
47 return "ALARM: Niveau d'agressivité très élevé !";
48 }
49
50 return "Status: Sécurisé";
51}
52
53const trex: DinosaurData = {
54 name: "T-Rex",
55 isAlive: true,
56 health: 85,
57 aggressionLevel: 6,
58 enclosure: { fence: { isActive: true, voltage: 10000 } },
59 lastFed: Date.now() - 3600000
60};
61
62const brokenFence: DinosaurData = {
63 name: "Velociraptor",
64 isAlive: true,
65 health: 90,
66 aggressionLevel: 9,
67 enclosure: { fence: { isActive: false, voltage: 0 } }
68};
69
70console.log(`${trex.name}: ${checkSafety(trex)}`);
71console.log(`${brokenFence.name}: ${checkSafety(brokenFence)}`);
72
73// ===========================================
74// 2. Validation avec retours anticipés
75// ===========================================
76console.log("\n=== 2. VALIDATION DU FORMULAIRE ===");
77
78interface VisitorForm {
79 firstName?: string;
80 lastName?: string;
81 age?: number;
82 email?: string;
83 acceptedTerms?: boolean;
84}
85
86function validateVisitor(form: VisitorForm): { valid: boolean; error?: string } {
87 if (!form.firstName) {
88 return { valid: false, error: "Prénom manquant" };
89 }
90
91 if (!form.lastName) {
92 return { valid: false, error: "Nom manquant" };
93 }
94
95 if (!form.age || form.age < 5) {
96 return { valid: false, error: "Âge minimum: 5 years old" };
97 }
98
99 if (!form.email || !form.email.includes("@")) {
100 return { valid: false, error: "Email invalide" };
101 }
102
103 if (!form.acceptedTerms) {
104 return { valid: false, error: "Acceptation des conditions requise" };
105 }
106
107 return { valid: true };
108}
109
110const goodForm: VisitorForm = {
111 firstName: "Jean",
112 lastName: "Dupont",
113 age: 25,
114 email: "jean@parc.com",
115 acceptedTerms: true
116};
117
118const badForm: VisitorForm = {
119 firstName: "Anna",
120 age: 3
121};
122
123console.log("Formulaire valide:", validateVisitor(goodForm));
124console.log("Formulaire invalide:", validateVisitor(badForm));
125
126// ===========================================
127// 3. TODO : Essaie toi-même !
128// ===========================================
129console.log("\n=== 3. À TOI DE JOUER ===");
130console.log("Refactorise le code suivant en utilisant des early returns:");
131
132// TODO : Réécris cette fonction en utilisant des retours anticipés
133// au lieu de if-else imbriqués
134
135function processOrder(items: string[], payment: number) {
136 // Utilise des retours anticipés au lieu de conditions imbriquées !
137 if (items && items.length > 0) {
138 if (payment > 0) {
139 if (payment >= items.length * 10) {
140 console.log("Commande traitée !");
141 return true;
142 } else {
143 console.log("Montant insuffisant");
144 return false;
145 }
146 } else {
147 console.log("Paiement manquant");
148 return false;
149 }
150 } else {
151 console.log("Aucun produit");
152 return false;
153 }
154}
155
156processOrder(["Billet VIP", "Lunch"], 50);
157processOrder([], 10);
158processOrder(["Billet"], 5);
159
160console.log("\nAstuce: Utilise la négation des conditions et return au début !");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 que l'« anti-pattern de la flèche » (Pyramid of Doom) dans le code ?
2. Que retourne
dino?.enclosure?.location ?? nullquanddinovautundefined?
Tâches pratiques dans le jeu
- Tri vertical
Ordonne les éléments d'une fonction qui utilise des retours anticipés (de haut en bas) :
- Clique dans l'ordre
Ordonne les éléments d’une clause de garde :