Types avancés de TypeScript expliqués avec des exemples

TypeScript propose plusieurs types avancés qui vont au-delà des types de base, permettant des systèmes de types plus flexibles et plus puissants. Ces types avancés aident à créer des applications robustes en fournissant des moyens supplémentaires pour définir et appliquer des contraintes de type. Cet article explore certains de ces types avancés avec des exemples.

Types de syndicats

Les types d'union permettent à une variable d'être de plusieurs types. Cela peut être utile lorsqu'une valeur peut être de plusieurs types mais doit être gérée de manière appropriée en fonction de son type réel.

// Union type example

function formatValue(value: string | number): string {
  if (typeof value === 'string') {
    return `String: ${value}`;
  } else {
    return `Number: ${value.toFixed(2)}`;
  }
}

console.log(formatValue("Hello"));
console.log(formatValue(123.456));

Dans cet exemple, la fonction `formatValue` accepte soit une chaîne soit un nombre et formate la valeur en conséquence.

Types d'intersections

Les types d'intersection combinent plusieurs types en un seul. Un objet d'un type d'intersection aura toutes les propriétés des types combinés. Ceci est utile pour composer plusieurs types ensemble.

// Intersection type example

interface Person {
  name: string;
  age: number;
}

interface Contact {
  email: string;
  phone: string;
}

type Employee = Person & Contact;

const employee: Employee = {
  name: "John Doe",
  age: 30,
  email: "john.doe@example.com",
  phone: "123-456-7890"
};

console.log(employee);

Ici, le type « Employé » est une intersection de « Personne » et « Contact », ce qui signifie qu'il contient des propriétés des deux interfaces.

Types littéraux

Les types littéraux spécifient les valeurs exactes qu'une variable peut contenir. Cela peut être particulièrement utile pour garantir que seules certaines valeurs spécifiques sont autorisées.

// Literal type example

type Direction = "up" | "down" | "left" | "right";

function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

move("up");    // Valid
move("down");  // Valid
// move("side"); // Error: Argument of type '"side"' is not assignable to parameter of type 'Direction'.

Le type « Direction » ici est limité à quatre valeurs de chaîne spécifiques, garantissant que seules ces directions peuvent être utilisées dans la fonction « move ».

Types de tuples

Les types de tuple représentent un tableau avec un nombre fixe d'éléments où chaque élément peut avoir un type différent. Les tuples sont utiles pour représenter des collections de taille fixe d'éléments hétérogènes.

// Tuple type example

let user: [string, number] = ["Alice", 30];

console.log(user[0]); // "Alice"
console.log(user[1]); // 30

// user = [30, "Alice"]; // Error: Type 'number' is not assignable to type 'string'.

Le tuple « utilisateur » est défini avec une chaîne suivie d'un nombre, et cette structure doit être maintenue.

Types conditionnels

Les types conditionnels permettent de déterminer les types en fonction de conditions. Ils permettent de sélectionner un type ou un autre en fonction d'une condition.

// Conditional type example

type IsString = T extends string ? "Yes" : "No";

type Test1 = IsString;  // "Yes"
type Test2 = IsString;  // "No"

Dans cet exemple, le type `IsString` vérifie si un type `T` est une chaîne. Il renvoie `"Yes"` si c'est le cas et `"No"` sinon.

Types mappés

Les types mappés permettent de créer de nouveaux types en transformant les propriétés d'un type existant. Cela est utile pour modifier ou étendre les types existants.

// Mapped type example

type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K];
};

const readonlyPerson: ReadonlyPerson = {
  name: "Alice",
  age: 30
};

// readonlyPerson.age = 31; // Error: Cannot assign to 'age' because it is a read-only property.

Le type `ReadonlyPerson` transforme le type `Person` en rendant toutes ses propriétés en lecture seule.

Conclusion

Les types avancés de TypeScript fournissent des outils puissants pour définir et gérer des exigences de type complexes. En utilisant des types d'union, d'intersection, littéraux, de tuple, conditionnels et mappés, les développeurs peuvent créer des applications plus robustes et plus faciles à gérer. La compréhension et l'application efficaces de ces types peuvent améliorer considérablement la sécurité et la flexibilité des types du code TypeScript.