Mutable et Immutable en TypeScript
Cet article explique les concepts de mutable et immutable en TypeScript.
YouTube Video
Mutable et Immutable en TypeScript
Qu'est-ce que le Mutable ?
Mutable signifie qu'une valeur peut être modifiée. Les types par référence comme les objets et les tableaux sont des exemples typiques de structures de données mutables.
Exemple d'un objet mutable
1type Person = { name: string; age: number };
2
3// Mutable Example: Object
4let person: Person = { name: "Alice", age: 25 };
5person.age = 26;
6console.log(person); // { name: "Alice", age: 26 }
Dans ce code, la propriété age
de l'objet person
est modifiée de 25
à 26
. Étant donné que les objets sont passés par référence, le contenu à l'adresse mémoire stockée dans la variable person
est modifié.
Exemple d'un tableau mutable
1// Mutable Example: Array
2let numbers: number[] = [1, 2, 3];
3numbers.push(4);
4console.log(numbers); // [1, 2, 3, 4]
Dans ce code, la méthode push
est utilisée pour ajouter un nouvel élément 4
au tableau d'origine. Cela modifie le tableau d'origine, ce qui en fait une opération mutable.
Exemple dans une fonction
1// Mutable Example: Function
2function append(arr: number[], value: number): void {
3 arr.push(value); // Modify the original array
4 console.log(arr);
5}
6
7let nums: number[] = [1, 2, 3];
8append(nums, 4);
9console.log(nums); // [1, 2, 3, 4]
Lorsqu'on effectue des opérations mutables à l'intérieur d'une fonction, le tableau d'origine est également modifié.
Qu'est-ce que l'Immutable ?
Immutable signifie qu'une valeur ne peut pas être modifiée. Les types primitifs sont fondamentalement immutables.
Exemple d'un type primitif immutable
1// Immutable Example: String
2let str: string = "hello";
3str[0] = "H"; // Error: Index assignment is not allowed
4console.log(str); // "hello"
Tenter de changer le premier caractère de la chaîne str
en H
échoue parce que les chaînes sont immutables.
Exemple dans une fonction
1// Immutable Example: Function
2function increment(num: number): number {
3 num++; // This modifies only the local copy of num
4 return num;
5}
6
7let number: number = 10;
8console.log(increment(number)); // 11
9console.log(number); // 10 (original number remains unchanged)
Comme les nombres sont immutables, les opérations dans une fonction n'affectent pas la variable d'origine.
Opérations immutables sur les tableaux
Les tableaux sont mutables, mais en créant un nouveau tableau au lieu de modifier l'original, des opérations immutables peuvent être réalisées.
1// Create an array of numbers
2let numbers: number[] = [1, 2, 3];
3
4// Immutable Example: Creating a new array
5let newNumbers: number[] = [...numbers, 4];
6
7console.log(numbers); // [1, 2, 3] (original array is unchanged)
8console.log(newNumbers); // [1, 2, 3, 4] (new array with an added element)
Ici, la syntaxe de décomposition (...
) est utilisée pour créer un nouveau tableau newNumbers
. Comme le tableau numbers
original reste inchangé, il s'agit d'une opération immuable.
Avantages d'utiliser des structures de données immuables
Amélioration de la prévisibilité
Les données immuables ne changent pas, ce qui rend les modifications inattendues moins probables et réduit les risques de bogues.
Compatibilité avec des bibliothèques basées sur l'immuabilité
Les bibliothèques telles que React
et Redux
sont souvent conçues sur la base de données immuables, ce qui facilite la gestion de l'état lorsqu'elles sont utilisées correctement.
Rendre les objets immuables avec Object.freeze
Object.freeze
peut être utilisé pour empêcher les modifications d'un objet.
1// Create a frozen object (properties cannot be modified)
2const person = Object.freeze({ name: "Alice", age: 25 });
3
4// Attempt to modify a property (ignored in non-strict mode, error in strict mode)
5person.age = 26;
6
7console.log(person); // { name: "Alice", age: 25 }
Cependant, Object.freeze
effectue uniquement un gel superficiel, ce qui signifie que les propriétés des objets imbriqués restent modifiables.
1// Create a frozen object with a nested object
2const user: Readonly<{ profile: { name: string } }> = Object.freeze({
3 profile: { name: "Bob" }
4});
5
6// Attempt to modify a nested property (this works because Object.freeze() is shallow)
7user.profile.name = "Charlie"; // No TypeScript error, but still mutable
8
9console.log(user.profile.name); // "Charlie" (nested object is still mutable)
Pour créer un objet complètement immuable, un gel profond est nécessaire.
1// Function to deeply freeze an object, making all nested objects immutable
2function deepFreeze<T>(obj: T): Readonly<T> {
3 Object.freeze(obj);
4 Object.getOwnPropertyNames(obj).forEach(prop => {
5 const value = (obj as any)[prop];
6 if (typeof value === "object" && value !== null) {
7 deepFreeze(value);
8 }
9 });
10 return obj;
11}
12
13// Create a deeply frozen object
14const user = deepFreeze({
15 profile: { name: "Bob" }
16});
17
18// Attempt to modify a nested property
19// (this will now throw an error in strict mode)
20user.profile.name = "Charlie"; // No TypeScript error, but modification is not allowed at runtime
21
22console.log(user.profile.name); // "Bob" (unchanged due to deep freeze)
Résumé
- Les données mutables sont modifiables, et incluent les objets et les tableaux.
- Les données immuables sont non modifiables, et incluent les types primitifs tels que les chaînes de caractères et les nombres.
- En utilisant la syntaxe de décomposition ou des méthodes comme
map
, des opérations sur des données immuables peuvent être effectuées. Object.freeze
etdeepFreeze
peuvent être utilisés pour empêcher les modifications des objets.- L'utilisation de données immuables aide à écrire un code plus prévisible et moins sujet aux erreurs.
Adopter une conception immuable améliore la sécurité et la lisibilité du code, alors profitez-en pleinement !
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.