Narrowing en français

Qu'est-ce que le narrowing ?

Le narrowing est un concept dans TypeScript qui permet de préciser une valeur qui peut être de plusieurs types à un type unique et spécifique. Dans TypeScript, les types unis représentent des entités pouvant prendre deux types ou plus. Afin d'accéder à des membres non partagés de ces différents types, il est nécessaire de réduire la valeur à un type plus précis avant de l'utiliser.

Quand le narrowing se produit-il ?

TypeScript identifie que le type d'une valeur a été "réduit" lorsqu'il rencontre des structures de contrôle de flux en JavaScript, notamment : - Les instructions conditionnelles telles que if/else, les ternaires et les switches. - Les boucles, comme for et while. - Les vérifications de vérité pour des entités qui ne représentent pas des valeurs équivalentes à false.

Ainsi, si un segment de code ne peut être atteint que si une valeur est d'un type particulier, TypeScript inférera que la valeur est de ce type dans le cadre de ce flux de contrôle.

Exemple de narrowing avec un if statement

Considérons la fonction suivante logValueIfExists(), qui prend en paramètre une valeur de type string | undefined. Pour que TypeScript réduise explicitement notre valeur à un type string, nous pouvons utiliser une instruction if agissant comme un "garde de type".

function logValueIfExists(value: string | undefined) {
  if (typeof value === 'string') {
    console.log(`Super ! ${value}!`);
  }
}
logValueIfExists('narrowing'); // output: Super ! narrowing!

Lorsque nous appelons la fonction avec la valeur de type string, le code à l'intérieur de l'instruction if s'exécutera et le texte sera affiché dans la console.

Exemple de narrowing avec la truthiness

Dans l'exemple ci-dessous, nous avons modifié légèrement l'instruction if pour vérifier si la valeur est "truthy", c'est-à-dire qu'elle ne doit pas évaluer à une valeur falsy comme 0, false ou undefined.

function logValueIfExists(value: string | undefined) {
  value; // Type: string | undefined 
  if (value) {
    console.log(`Super ! ${value}!`);
    value; // Type: string
    value.length; // Type: number
  }
  value.length; // Erreur : l'objet est potentiellement 'undefined'.
}
logValueIfExists('truthiness'); // output: Super ! truthiness!
let newValue;
logValueIfExists(newValue); // newValue est "undefined" ; rien n'est affiché.

En dehors de l'instruction if, la valeur est toujours considérée comme un type unifié (string | undefined), donc appeler value.length entraînerait une erreur. Cependant, à l'intérieur de l'instruction if, la valeur a été réduite à un type string, ce qui permet d'accéder à la propriété length.