Aller au contenu principal

Publié le · Mis à jour le 2 octobre 2026

Utiliser les object literals pour améliorer les conditions

Dimitri Dumont
Dimitri Dumont

Développeur React & Next.js freelance

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. Ces instructions sont simples à utiliser et connues de tous les développeurs, mais elles présentent certains inconvénients qui peuvent réduire la qualité et la lisibilité du code.

L'objectif de cet article est de vous présenter les object literals pour déclarer des conditions en TypeScript. Le but est de vous donner un outil supplémentaire pour définir vos conditions et améliorer la qualité de votre code.

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 de tous les développeurs.

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

Cependant, cette méthode devient contraignante dès que les conditions se complexifient ou que le nombre de cas possibles augmente :

const getStatusMessage = (status: string): string => {
    if (status === 'success') {
        return 'Operation was successful.';
    } else if (status === 'error') {
        return 'There was an error.';
    } else if (status === 'loading') {
        return 'Loading...';
    } else {
        return 'Unknown status.';
    }
}
 
console.log(getStatusMessage('success'));  // Output: Operation was successful.

Pour faciliter la lisibilité et la maintenabilité de ce code, 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 qu'un cas est trouvé. Si aucun cas n'est trouvé, une instruction par défaut peut être exécutée. Elle est souvent déclarée à la fin des différents cas.

const getStatusMessage = (status: string): string => {
    switch (status) {
        case 'success':
            return 'Operation was successful.';
        case 'error':
            return 'There was an error.';
        case 'loading':
            return 'Loading...';
        default:
            return 'Unknown status.';
    }
}
 
console.log(getStatusMessage('error'));  // Output: There was an error.

Le problème avec l'instruction switch est qu'elle devient verbeuse dès que le nombre de cas augmente. De plus, quand un cas ne se termine pas par un return, il ne faut pas oublier d'ajouter l'instruction break, sinon l'exécution se poursuit dans le cas suivant.

Un autre problème de l'instruction switch est qu'elle ne respecte pas le principe open/closed des principes SOLID.

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

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 stockent des paires clé/valeur.

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

const getStatusMessage = (status: string): string => {
    const statusMessages: { [key: string]: string } = {
        success: 'Operation was successful.',
        error: 'There was an error.',
        loading: 'Loading...',
        default: 'Unknown status.'
    };
 
    return statusMessages[status] || statusMessages.default;
}
 
console.log(getStatusMessage('loading'));  // Output: Loading...

Contrairement à l'instruction if/else, nous n'avons pas besoin de vérifier chaque condition une par une. Pour ajouter un nouveau cas, il suffit d'ajouter une entrée dans l'objet. Pour ajouter une condition par défaut, il suffit d'une entrée avec une clé par défaut.

Comparé à l'instruction switch, il n'y a pas de break à gérer. De plus, les object literals permettent de respecter le principe open/closed des principes SOLID.

Application du principe Open/Closed aux conditions

Le principe open/closed fait partie des principes SOLID, un ensemble de bonnes pratiques pour écrire du code maintenable et évolutif. 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 à une classe, une fonction ou un module sans modifier le code existant. Cela limite les risques d'introduire des bugs ou de casser des fonctionnalités existantes.

Prenons un exemple classique avec 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 la modification peut affecter des comportements qui fonctionnaient.

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

const getStatusMessage = (status: string): string => {
    switch (status) {
        case 'success':
            return 'Operation was successful.';
        case 'error':
            return 'There was an error.';
        case 'loading':
            return 'Loading...';
        default:
            return 'Unknown status.';
    }
}

Dans cet exemple, si on veut ajouter un nouveau statut (par exemple pending), il faut modifier la fonction getStatusMessage en ajoutant un nouveau case.

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

const statusMessages: { [key: string]: string } = {
    success: 'Operation was successful.',
    error: 'There was an error.',
    loading: 'Loading...',
    default: 'Unknown status.'
};
 
const getStatusMessage = (status: string): string => {
    return statusMessages[status] || statusMessages.default;
}

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

Le respect du principe open/closed apporte :

  • 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 un comportement ne nécessite pas de toucher au cœur de la logique.
  • Maintenabilité : un nouveau développeur peut ajouter un cas en complétant l'objet statusMessages, sans avoir à comprendre ni réécrire toute la logique.

Typer les clés avec Record

Les exemples précédents acceptent n'importe quelle chaîne de caractères en entrée. Cette souplesse a deux défauts. TypeScript ne signale pas un statut oublié. Et une clé comme toString ou constructor existe sur tous les objets JavaScript : statusMessages['toString'] renvoie une fonction héritée du prototype, pas le message par défaut.

Quand la liste des cas est connue, une union de chaînes et le type Record règlent les deux problèmes :

type Status = 'success' | 'error' | 'loading';
 
const statusMessages: Record<Status, string> = {
    success: 'Operation was successful.',
    error: 'There was an error.',
    loading: 'Loading...',
};
 
const getStatusMessage = (status: Status): string => statusMessages[status];

Si un statut pending est ajouté au type Status, TypeScript refuse de compiler tant que l'objet statusMessages n'a pas d'entrée correspondante. Le cas par défaut devient inutile, puisque toutes les valeurs possibles sont couvertes.

FAQ

Quand utiliser un object literal plutôt qu'un switch ?

Privilégier les object literals dès que le nombre de cas dépasse 3 ou 4. Le switch reste adapté quand plusieurs cas partagent le même traitement ou quand chaque cas contient une logique différente. Les object literals conviennent mieux aux correspondances clé/valeur sans logique complexe entre les cas.

Les object literals fonctionnent-ils avec des fonctions comme valeurs ?

Oui, les valeurs peuvent être des fonctions, pas uniquement des primitives. Cela permet d'exécuter une logique différente selon la clé. Par exemple : const actions = { save: () => saveData(), delete: () => deleteData() }. L'appel se fait avec actions[action]?.().

Comment gérer les types TypeScript avec les object literals ?

Définir une union de chaînes pour les clés valides, puis typer l'objet avec Record. Par exemple : type Status = 'success' | 'error' | 'loading' et Record<Status, string>. TypeScript garantit alors que toutes les clés sont présentes et que les valeurs sont du bon type. L'opérateur satisfies Record<Status, string> fait la même vérification en conservant le type littéral de chaque valeur.

Les object literals sont-ils plus performants que switch ?

La différence de performance est négligeable dans la plupart des cas. Le choix doit se baser sur la lisibilité et la maintenabilité du code, pas sur des micro-optimisations.

Conclusion

Les object literals sont un bon outil pour définir des conditions avec de nombreux cas. Ils rendent le code plus lisible, plus maintenable et conforme au principe open/closed.

Comme tout outil, cette technique s'utilise quand elle est la plus appropriée. Pour une condition simple, l'instruction if/else reste préférable. Pour une correspondance entre des valeurs connues et un résultat, les object literals typés avec Record sont plus sûrs.

Dimitri Dumont

Dimitri Dumont

Développeur React & Next.js freelance depuis 8 ans, 33 entreprises accompagnées depuis 2018. J'écris ici ce que je constate en mission : un produit ralentit presque toujours pour les mêmes raisons, une architecture posée dans l'urgence, pas de tests, une mise en production qui fait peur. Mon travail consiste à construire des produits qui n'en arrivent pas là, et à remettre sur pied ceux qui y sont déjà. Mon parcours

La suite

Ce que ça donne sur votre code

Lire un article et lire une vraie codebase sont deux exercices différents. Je lis la vôtre et je vous dis ce qui ralentit, ce que ça coûte de le corriger, et dans quel ordre.

Articles similaires