Logo dévoreur 2 code
Blog

Manipulation des types complexes : Union, Intersection et Typeguards en TypeScript

Fabien Schlegel

Fabien Schlegel

6 min

publié le : 29/11/2023

#typescript
Image d'illustration pour Manipulation des types complexes : Union, Intersection et Typeguards en TypeScript

Lorsqu'il s'agit de construire des applications robustes en TypeScript, la manipulation des types complexes est rapidement indispensable.

Comprendre en profondeur les notions d'unions, d'intersections et de typeguards devient un atout majeur pour les développeuses et les développeurs cherchant à renforcer la sûreté de leur code.

Introduction

Les types complexes, tels que les unions et les intersections, représentent un ensemble de possibilités avancées pour structurer les données en TypeScript.

Les unions permettent la création de types qui peuvent contenir plusieurs types différents, tandis que les intersections permettent de combiner plusieurs types pour former un seul type.

Le typeguards aident à garantir la sécurité du code en permettant de valider les données lors de l’exécution du programme.

Unions et Intersections

Explication des unions et de leur utilisation

Les unions offrent une flexibilité remarquable pour définir des types capables de représenter plusieurs formes. Par exemple :

type ID = string | number;
let userId: ID;

userId = 'abc123'; // OK
userId = 456; // OK
userId = true; // Error: Type 'boolean' is not assignable to type 'string | number'

Approfondissement sur les intersections et leur utilisation efficace

À l'opposé des unions, les intersections permettent de fusionner des types pour créer un nouveau type possédant toutes les caractéristiques de ses composants :

interface Car {
  brand: string;
  color: string;
}

interface Electric {
  batteryLife: number;
}

type ElectricCar = Car & Electric;

let myCar: ElectricCar;
myCar = {
  brand: 'Tesla',
  color: 'Red',
  batteryLife: 300,
};

Comparaison des cas d'utilisation pour choisir entre unions et intersections

La décision d'utiliser des unions ou des intersections dépend souvent du contexte et de la logique applicative.

Les unions sont idéales pour représenter une valeur pouvant être de plusieurs types distincts, tandis que les intersections sont plus adaptées pour combiner des types pour créer un nouveau type complet.

Typeguards : Gardiens de la sûreté du code

Les typeguards, ou gardiens de type, sont des fonctions qui permettent de vérifier le type d'une variable à l'exécution.

Ils garantissent ainsi une meilleure sécurité et précision dans le traitement des données.

Exemples concrets illustrant l'utilisation des typeguards pour sécuriser le code

Dans l’exemple, on veut calculer l’aire d’une forme. Et le calcul change suivant la forme utilisé. Grâce au mot clé in, on va pouvoir vérifier la présence d’une propriété exclusive à notre forme et utiliser la bonne formule.

interface Square {
  size: number;
}

interface Rectangle {
  width: number;
  height: number;
}

interface Circle {
  radius: number
}

type Shape = Square | Rectangle | Circle;

function calculateArea(shape: Shape): number {
  if ("size" in shape) return shape.size ** 2; // Calcul de l'aire pour un carré

  if ("radius" in shape) return Math.PI * shape.radius ** 2 // Calcul de l'aire pour un cercle

  return shape.width * shape.height; // Calcul de l'aire pour un rectangle

Dans cet exemple, on veut vérifier si notre animal est un chien ou un chat et afficher ses informations. Dans le cas où on ne peut pas l’identifier, on va lever une exception.

interface Dog extends Animal {
  breed: string;
}

interface Cat extends Animal {
  color: string;
}

function isDog(animal: any): animal is Dog {
  return animal && animal.breed !== undefined;
}

function isCat(animal: any): animal is Cat {
  return animal && animal.color !== undefined;
}

function processAnimal(animal: Animal) {
  if (isDog(animal)) return console.log(`Dog: ${animal.name}, Breed: ${animal.breed}`);

  if (isCat(animal)) return console.log(`Cat: ${animal.name}, Color: ${animal.color}`);

  throw new Error('Aie, cet animal est inconnu');
}

const dog: Dog = {
  name: 'Buddy',
  breed: 'Golden Retriever',
};

const cat: Cat = {
  name: 'Whiskers',
  color: 'Gray',
};

processAnimal(dog); // Output: Dog: Buddy, Breed: Golden Retriever
processAnimal(cat); // Output: Cat: Whiskers, Color: Gray

Bonnes pratiques et astuces pour optimiser l'emploi des typeguards

Nommage des fonctions de typeguards : Donnez des noms clairs et explicites aux fonctions de typeguards pour faciliter la compréhension et améliorer la lisibilité du code.

function isManager(employee: Employee): employee is Manager {
  return (employee as Manager).department !== undefined;
}

Usage de as ou in avec précaution : Utilisez as et in de manière judicieuse et précise pour éviter des conversions ou vérifications inutiles qui pourraient altérer la sûreté du code.

if ('department' in employee) {
  // Faites quelque chose...
}

Combiner les typeguards : Utilisez plusieurs typeguards combinés pour des vérifications plus complexes.

function isSeniorManager(employee: Employee): boolean {
  return isManager(employee) && employee.department === 'Engineering';
}

Extension de typeguards : Étendez les fonctionnalités des typeguards pour des cas plus spécifiques ou des conditions supplémentaires.

function isSeniorManager(employee: Employee): boolean {
  return isManager(employee) && employee.department === 'Engineering';
}

Éviter la redondance de code : Réutilisez les typeguards existants pour éviter la duplication de vérifications similaires.

function isEmployeeSenior(employee: Employee): boolean {
  return isManager(employee) || isSeniorManager(employee);
}

En suivant ces bonnes pratiques et astuces, vous pouvez maximiser l'efficacité et la clarté de vos typeguards, renforçant ainsi la sûreté et la fiabilité de votre code TypeScript.

Cas d'utilisation avancés

Gestion des états dans une application

Dans cet exemple on utilise l’union pour les types des différents états et des typeguards qui permet de vérifier que les données sont présentes pour les afficher.

De cette manière, on peut anticiper le contenu de la variable state et le comportement de la fonction handleState.

type LoadingState = {
  loading: true;
};

type SuccessState<T> = {
  loading: false;
  data: T;
};

type ErrorState = {
  loading: false;
  error: string;
};

type State<T> = LoadingState | SuccessState<T> | ErrorState;

function handleState<T>(state: State<T>) {
  if (state.loading) {
    // Afficher l'indicateur de chargement
  } else if ('data' in state) {
    // Utiliser state.data
  } else {
    // Afficher l'erreur : state.error
  }
}

Dans cet exemple, on utilise la combinaison de typeguards et une intersection. Cela va permettre de vérifier le type de l’élément box pour s’assurer qu’il contient bien les propriétés indispensables lors d’un traitement spécifique. On évite ainsi les erreurs.

type BoxTypes = ImageBox | StaticTextBox | TagTextBox | SocialMediaBox | TagImageBox | GroupBox;

function isTagBox(box: BoxTypes): box is TagTextBox | TagImageBox {
  return isTagTextBox(box) || isTagImageBox(box);
}

Conclusion

La manipulation avancée des types complexes tels que les unions, les intersections et les typeguards ouvre un monde de possibilités pour les développeuses et les développeurs TypeScript.

En comprenant ces concepts et en les appliquant judicieusement, vous renforcez la robustesse et la sûreté de votre code, tout en simplifiant la gestion des structures de données complexes.

En explorant en profondeur les unions et les intersections, en maîtrisant les typeguards pour sécuriser vos opérations de typage, et en appliquant ces connaissances dans des scénarios concrets, vous êtes armés pour élever votre développement en TypeScript à de nouveaux sommets.

Continuez d'explorer ces concepts, expérimentez-les dans vos projets et découvrez comment ils peuvent transformer fondamentalement votre approche du développement logiciel.

Articles associés


Image d'illustration pour l'article

TypeScript : types, interfaces et classes

Explorons les bases de TypeScript, en mettant l'accent sur les types, les interfaces et les classes. Apprenez comment les utiliser pour améliorer la robustesse de votre code TypeScript.

Lire l'article

8 min
Image d'illustration pour l'article

Les enums en Typescript

Les enums TypeScript simplifient le code et améliorent la lisibilité. Cet article complet explore le concept des enums, leur syntaxe, leurs avantages et les meilleures pratiques.