Écrire un composant React en TypeScript
Marcos Musafiri

Marcos Musafiri

14/09/2022

Catégorie: App Development

Écrire un composant React en TypeScript

Au cours des dernières années, TypeScript a gagné une immense popularité parmi les développeurs front-end. L'amélioration de la maintenabilité, la cohérence du code et la prise en charge des futurs navigateurs sont quelques-unes des raisons de son succès. Bien que de nombreux autres frameworks et bibliothèques adoptent TypeScript par défaut, React est resté neutre, laissant aux développeurs la possibilité de choisir entre TypeScript et JavaScript.

Dans cet article, j'aborderai la création d'un composant React avec Typescript.

Voici notre composant sans les types :

  
    const operations = {
      '+': (left, right) => left + right,
      '-': (left, right) => left - right,
      '*': (left, right) => left * right,
      '/': (left, right) => left / right,
    }

    function Calculator({left, operator, right}){
       const result = operations[operator](left, right);
       return (
         div
           code
              {left} {operator} {right} = output{result}/output
           /code
          /div
        );
    }

    const examples = (
      
        Calculator left={1} operator="+" right={2} /
        Calculator left={1} operator="-" right={2} /
        Calculator left={1} operator="*" right={2} /
        Calculator left={1} operator="/" right={2} /
      
    )
  

Là, vous pouvez remarquer que nous faisons les choses un peu différemment. Peut-être préférez-vous ceci à la place :

  
    const Calculator({left, operator, right})=>(
      div
         code
            {left} {operator} {right} = {' '}
            output{operations[operator](left, right)}/output
         /code
       /div
    );
  

Je n'aime pas le retour implicite. Cela signifie que vous ne pouvez pas raisonnablement déclarer des variables ou utiliser des hooks. Donc, même pour des composants simples, je ne suis jamais cette approche.

Ok, donc peut-être que vous faites ça :

  
    const Calculator({left, operator, right})=>{
       const result = operations[operator](left, right);
       return (
         div
           code
              {left} {operator} {right} = output{result}/output
           /code
          /div
        );
    }
  

Honnêtement, c'est très bien la plupart du temps. Personnellement, je préfère les caractéristiques de levage des déclarations de fonction plutôt que les expressions de fonction de ce type.

Très bien, ajoutons des types à cela. Pour les fonctions, vous devez prendre en compte les types qui entrent et ceux qui sortent. Commençons par l'entrée : props. Pour commencer, prenons un type simple pour les props (nous l'améliorerons plus tard) :

  
    type CalculatorProps = {
      left: number;
      operator: string;
      right: number
    }
  

Avec cela, essayons quelques options pour appliquer ce type à l'objet props dans notre composant React.

Une méthode courante de typage d'un composant React consiste à utiliser l'un des génériques qui sont intégrés à `@types/react` (Je veux dire, c'est intégré, n'est-ce pas ? Alors qu'est-ce qui pourrait mal tourner ?). Il est intéressant de noter que vous ne pouvez pas saisir une déclaration de fonction de cette manière, nous devrons donc utiliser une expression de fonction :

  
    const Calculator: React.FCCalculatorProps = ({left, operator, right}) => {
      // mise en œuvre coupée pour des raisons de brièveté
    }
  

Cela fonctionne assez bien, mais il y a trois problèmes majeurs avec cette méthode :

1. Notre fonction `Calculator` accepte maintenant un prop `children`, même si nous n'en faisons rien (Donc, ça se compile : Calculator left={1} operator="+" right={2}What?/Calculator

2. Vous ne pouvez pas utiliser de génériques. Ce n'est pas très courant, mais c'est un inconvénient.

3. Nous devons utiliser une expression de fonction et ne pouvons pas utiliser une déclaration de fonction.

Ok ok, peut-être que #3 n'est pas un problème majeur, mais #1 est assez significatif. Il y a quelques autres problèmes plus petits exposés dans cet excellent problème GitHub si vous voulez plonger plus profondément (consultez également la React TypeScript Cheatsheet ). Il suffit de dire qu'il ne faut pas utiliser `React.FC` (ou son alias plus long `React.FunctionComponent` )

Une des choses que j'aime à propos des composants React est qu'ils ne sont pas si spéciaux que ça. Voici la définition d'un composant React :

Un composant React est une fonction qui renvoie quelque chose que React peut afficher.

Maintenant, selon `@types/react` nous sommes limités à `null` et `JSX.Elements`, mais React peut aussi afficher des chaînes de caractères, des nombres et des booléens. Dans tous les cas, parce qu'un composant React est simplement une fonction qui renvoie quelque chose que React peut afficher, le taper peut être aussi simple que de taper des fonctions. Vous n'avez pas à faire quoi que ce soit de spécial simplement parce que c'est React.

Voici donc comment j'ai tapé les props de ce composant :

  
  function Calculator({left, operator, right }: CalculatorProps){
    // mise en œuvre coupée pour des raisons de brièveté
  }
  

Cette méthode ne présente aucun des inconvénients de `React.FC` et n'est pas plus compliquée que de saisir les arguments d'une fonction ordinaire.

Amélioration du type `CalculatorProps`

Ok, la partie suivante n'a pas grand chose à voir avec le typage des composants React, mais j'ai pensé que vous la trouveriez intéressante de toute façon, alors passez votre chemin si ce n'est pas le cas. Améliorons le type `CalculatorProps`. Pour rappel, voici ce que nous avons jusqu'à présent :

  
    J'ai pris la liberté de taper chacune de ces fonctions également :
    const operations = {
      '+': (left, right) => left + right,
      '-': (left, right) => left - right,
      '*': (left, right) => left * right,
      '/': (left, right) => left / right,
    }

    type CalculatorProps = {
      left: number;
      operator: string;
      right: number
    }

    function Calculator({left, operator, right}){
       const result = operations[operator](left, right);
       return (
         div
           code
              {left} {operator} {right} = output{result}/output
           /code
          /div
        );
    }
  

Je pense que les types `left` et `right` sont bien. C'est `operator` qui ne me convient pas. L'utilisation de la `string` est trop large. Il y a des opérations spécifiques qui sont autorisées. Par exemple, que se passerait-il si on essayait :

  
    const element = Calculator left={1} operator="wut" right={2} /
  

C'est ce qu'on appelle une exception d'exécution mes amis. C'est-à-dire... à moins que vous n'ayez activé le mode `strict`, auquel cas vous auriez une erreur de compilation sur `operations[operator]`. En mode strict, TypeScript saura correctement que l'accès à n'importe quelle chaîne de l'objet `operations` ne retournera pas nécessairement une fonction appelable.

Il existe de nombreuses façons de résoudre ce problème. Fondamentalement, nous voulons limiter `l'opérateur` aux seuls opérateurs pris en charge. Nous pouvons le faire avec un simple type d'union :

  
    type CalculatorProps = {
      left: number;
      operator: '+' | '-' | '*' | '/';
      right: number
    }
  

Mais si nous décidions d'ajouter l'opérateur d'exponentiation (`**`), nous devrions mettre à jour non seulement l'objet `opérations`, mais aussi le type `d'opérateur`, ce qui serait ennuyeux. Peut-être y a-t-il un moyen de dériver le type de `l'opérateur` à partir de l'objet `opérations` ? Oui, il y en a un !

  
    type CalculatorProps = {
      left: number;
      operator:  keyof typeof operations;
      right: number
    }
  

`typeof operations` va nous permettre d'obtenir un type qui décrit l'objet `operations`, ce qui est à peu près égal à :

  
    type operations = {
      '+': (left: number, right: number) => number;
      '-': (left: number, right: number) => number;
      '*': (left: number, right: number) => number;
      '/': (left: number, right: number) => number
    }
  

La partie `keyeof` prendra toutes les clés de ce type, ce qui donne lieu à '+' | '-' | '*' | '/'

Conclusion

Voici la version terminée (j'ai aussi tapé les fonctions des opérations) :

  
    type operations = {
      '+': (left: number, right: number) : number => left + right;
      '-': (left: number, right: number) : number => left - right;
      '*': (left: number, right: number) : number => left * right;
      '/': (left: number, right: number) : number => left / right
    }

    type CalculatorProps = {
      left: number;
      operator:  keyof typeof operations;
      right: number
    }

    function Calculator({left, operator, right }: CalculatorProps){
       const result = operations[operator](left, right);
       return (
         div
           code
              {left} {operator} {right} = output{result}/output
           /code
          /div
        );
     }

     const examples = (
      
        Calculator left={1} operator="+" right={2} /
        Calculator left={1} operator="-" right={2} /
        Calculator left={1} operator="*" right={2} /
        Calculator left={1} operator="/" right={2} /
      
    )
  

J'espère que cela vous donne une idée d'une bonne façon de taper vos composants React. Bonne chance et prenez soin de vous !

Contactez-nous .

Discutons de la manière dont Zabibu peut vous aider à atteindre vos objectifs commerciaux.