Utiliser les object literals pour améliorer les conditions

Publié le 4 septembre 2024
Dimitri Dumont avatar
Dimitri Dumont
Développeur front-end

Le code que nous écrivons contient souvent des conditions. Pour cela, nous pouvons utiliser les instructions if/else ou switch en Javascript et en Typescript. Bien que ces instructions soient simples à utiliser et connues par tous les développeurs, elles présentent certains inconvénients et peuvent ainsi réduire la qualité et la lisibilité du code.

L'objectif de cet article est de vous présenter les object literals dans le cas de la déclaration de conditions, en Typescript. Le but est de vous permettre d'avoir des outils supplémentaires pour définir vos conditions dans votre code et ainsi d'améliorer la qualité de celui-ci.

Inconvénients des conditions if/else

Pour définir une condition dans votre code, l'une des méthodes les plus simples est d'utiliser l'instruction if/else. Elle a l'avantage d'être simple, concise, et connue par tous les développeurs.

1if (role === 'utilisateur') {
2 // do something
3}

Cependant, cette méthode peut devenir contraignante dès qu'on commence à avoir des conditions plus complexes et/ou des conditions avec un certain nombre de cas possibles :

1const getStatusMessage = (status: string): string => {
2 if (status === 'success') {
3 return 'Operation was successful.';
4 } else if (status === 'error') {
5 return 'There was an error.';
6 } else if (status === 'loading') {
7 return 'Loading...';
8 } else {
9 return 'Unknown status.';
10 }
11}
12
13console.log(getStatusMessage('success')); // Output: Operation was successful.
14

Pour améliorer le code et ainsi faciliter la lisibilité et la maintenabilité de ce dernier, nous pouvons utiliser une autre instruction avec ses avantages et ses inconvénients : l'instruction switch.

Inconvénients des conditions switch

L'instruction switch permet d'exécuter du code dès lors qu'un cas est trouvé. Si aucun cas est trouvé, une instruction par défaut peut être réalisée. Cette instruction par défaut est souvent déclarée à la fin des différents cas.

1const getStatusMessage = (status: string): string => {
2 switch (status) {
3 case 'success':
4 return 'Operation was successful.';
5 case 'error':
6 return 'There was an error.';
7 case 'loading':
8 return 'Loading...';
9 default:
10 return 'Unknown status.';
11 }
12}
13
14console.log(getStatusMessage('error')); // Output: There was an error.
15

Le problème avec l'instruction switch est qu'elle peut être verbeuse dès que l'on commence à avoir un certain nombre de cas. De plus, si on souhaite que chaque cas soit traité de manière indépendante, il ne faut pas oublier d'ajouter l'instruction break à chaque fin de cas.

Un autre problème lorsqu'on utilise l'instruction switch est le fait de ne pas respecter le principe de open/closed des principes SOLID.

Pour répondre à ces problèmes, il existe une solution : les object literals.

hexa web logo
Hexa web
Des conseils pour un projet web ?
Nous contacter

Avantages des object literals en Typescript

Les object literals peuvent être utilisés pour définir plus efficacement des conditions dans notre code. Ce sont des objets Javascript qui permettent de stocker des paires clés/valeurs.

Voici un exemple d'utilisation des object literals pour définir une condition :

1const getStatusMessage = (status: string): string => {
2 const statusMessages: { [key: string]: string } = {
3 success: 'Operation was successful.',
4 error: 'There was an error.',
5 loading: 'Loading...',
6 default: 'Unknown status.'
7 };
8
9 return statusMessages[status] || statusMessages.default;
10}
11
12console.log(getStatusMessage('loading')); // Output: Loading...

Grâce aux object literals, nous pouvons définir des conditions complexes de manière plus lisible et plus maintenable.

Contrairement à l'instruction if/else, nous n'avons pas besoin de vérifier chaque condition une par une. De plus, si nous souhaitons ajouter un nouveau cas, il suffit d'ajouter une nouvelle entrée dans l'objet.

De même, si nous souhaitons ajouter une condition par défaut, nous pouvons ajouter une entrée avec une clé par défaut.

Comparé à l'instruction switch, il n'est pas nécessaire d'ajouter une instruction break à la fin de chaque cas. De plus, les object literals permettent de respecter le principe de open/closed des principes SOLID.

Application du principe Open/Closed aux conditions

Le principe open/closed fait partie des principes SOLID, qui sont un ensemble de bonnes pratiques pour écrire du code maintenable, évolutif, et flexible. Ce principe stipule que le code doit être ouvert à l'extension mais fermé à la modification.

Cela signifie qu'il devrait être possible d'ajouter de nouveaux comportements ou fonctionnalités à une classe, une fonction, ou un module, sans avoir à modifier le code existant. Cela permet de limiter les risques d'introduire des bugs ou de casser des fonctionnalités existantes lorsque le code est modifié.

Prenons un exemple classique avec l'utilisation d'une structure if/else ou switch. Chaque fois que vous voulez ajouter une nouvelle condition, vous devez modifier le code existant pour gérer le nouveau cas. Cela va à l'encontre du principe open/closed car le code doit être modifié, et potentiellement, cela peut affecter des comportements précédemment fonctionnels.

Exemple avec switch (non conforme au principe open/closed) :

1const getStatusMessage = (status: string): string => {
2 switch (status) {
3 case 'success':
4 return 'Operation was successful.';
5 case 'error':
6 return 'There was an error.';
7 case 'loading':
8 return 'Loading...';
9 default:
10 return 'Unknown status.';
11 }
12}

Dans cet exemple, si on veut ajouter un nouveau statut (par exemple pending), il faut modifier la fonction getStatusMessage en ajoutant un nouveau case. Cela augmente les risques de créer des erreurs et rend le code moins évolutif au fur et à mesure que les cas augmentent.

Exemple avec object literals (conforme au principe open/closed) :

1const statusMessages: { [key: string]: string } = {
2 success: 'Operation was successful.',
3 error: 'There was an error.',
4 loading: 'Loading...',
5 default: 'Unknown status.'
6};
7
8const getStatusMessage = (status: string): string => {
9 return statusMessages[status] || statusMessages.default;
10}

Dans cet exemple, si nous voulons ajouter un nouveau statut comme pending, il suffit d'ajouter une nouvelle clé/valeur à l'objet statusMessages, sans toucher à la fonction getStatusMessage. Ainsi, le code est ouvert à l'extension (on peut ajouter de nouvelles entrées dans l'objet), mais fermé à la modification (la fonction elle-même reste inchangée).

Le respect du principe open/closed permet ainsi :

  • Moins de risques d'erreurs : En ne modifiant pas le code existant, vous évitez de casser des comportements qui fonctionnent déjà.
  • Facilité d'extension : Ajouter de nouveaux comportements devient simple et ne nécessite pas de toucher au cœur de la logique, ce qui rend le code plus évolutif.
  • Maintenabilité : Le code est plus facile à comprendre et à maintenir dans le temps. Les nouveaux développeurs peuvent ajouter de nouveaux cas en modifiant une structure préexistante (comme l'objet statusMessages) sans avoir à comprendre et réécrire la logique entière.
hexa web logo
Hexa web
Des conseils pour un projet web ?
Nous contacter

Conclusion

Les object literals sont un outil puissant pour définir des conditions complexes et/ou longues. Ils permettent de rendre notre code plus lisible, plus maintenable et de respecter les principes SOLID.

Cependant, comme tout outil, il est important d'utiliser cette technique lorsque c'est nécessaire et qu'elle se présente comme la plus appropriée.

Si vous avez une condition simple, il est préférable d'utiliser l'instruction if/else. Si vous avez une condition complexe, vous pouvez utiliser les object literals.

Échangeons sur votre projet web

Présentez-nous votre projet web, nous vous recontacterons dans les prochaines 24h.