Français

Explorez les bonnes pratiques pour utiliser TypeScript avec React afin de créer des applications web robustes, évolutives et maintenables. Apprenez la structure de projet, la conception de composants, les tests et l'optimisation.

TypeScript avec React : Bonnes pratiques pour des applications évolutives et maintenables

TypeScript et React sont une combinaison puissante pour construire des applications web modernes. TypeScript apporte le typage statique à JavaScript, améliorant la qualité du code et la maintenabilité, tandis que React offre une approche déclarative et basée sur les composants pour construire des interfaces utilisateur. Ce billet de blog explore les meilleures pratiques pour utiliser TypeScript avec React afin de créer des applications robustes, évolutives et maintenables, adaptées à un public mondial.

Pourquoi utiliser TypeScript avec React ?

Avant de plonger dans les bonnes pratiques, comprenons pourquoi TypeScript est un ajout précieux au développement React :

Configuration d'un projet React TypeScript

Utiliser Create React App

Le moyen le plus simple de démarrer un nouveau projet React TypeScript est d'utiliser Create React App avec le modèle TypeScript :

npx create-react-app my-typescript-react-app --template typescript

Cette commande configure un projet React de base avec TypeScript, y compris les dépendances nécessaires et un fichier tsconfig.json.

Configuration de tsconfig.json

Le fichier tsconfig.json est le cœur de votre configuration TypeScript. Voici quelques paramètres recommandés :

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

Options clés à considérer :

Bonnes pratiques pour les composants React avec TypeScript

Typage des props des composants

L'un des aspects les plus importants de l'utilisation de TypeScript avec React est de typer correctement les props de vos composants. Utilisez des interfaces ou des alias de type pour définir la structure de l'objet props.

interface MyComponentProps {
  name: string;
  age?: number; // Prop optionnelle
  onClick: () => void;
}

const MyComponent: React.FC<MyComponentProps> = ({ name, age, onClick }) => {
  return (
    

Bonjour, {name} !

{age &&

Vous avez {age} ans.

}
); };

L'utilisation de React.FC<MyComponentProps> garantit que le composant est un composant fonctionnel et que les props sont correctement typées.

Typage de l'état du composant

Si vous utilisez des composants de classe, vous devrez également typer l'état du composant. Définissez une interface ou un alias de type pour l'objet d'état et utilisez-le dans la définition du composant.

interface MyComponentState {
  count: number;
}

class MyComponent extends React.Component<{}, MyComponentState> {
  state: MyComponentState = {
    count: 0
  };

  handleClick = () => {
    this.setState({
      count: this.state.count + 1
    });
  };

  render() {
    return (
      

Compteur : {this.state.count}

); } }

Pour les composants fonctionnels utilisant le hook useState, TypeScript peut souvent déduire le type de la variable d'état, mais vous pouvez également le fournir explicitement :

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  return (
    

Compteur : {count}

); };

Utilisation des Type Guards

Les Type Guards sont des fonctions qui restreignent le type d'une variable dans un champ d'application spécifique. Ils sont utiles lors de la gestion de types union ou lorsque vous devez vous assurer qu'une variable a un type spécifique avant d'effectuer une opération.

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  side: number;
}

type Shape = Circle | Square;

function isCircle(shape: Shape): shape is Circle {
  return shape.kind === "circle";
}

function getArea(shape: Shape): number {
  if (isCircle(shape)) {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.side ** 2;
  }
}

La fonction isCircle est un Type Guard qui vérifie si une Shape est un Circle. Dans le bloc if, TypeScript sait que shape est un Circle et vous permet d'accéder à sa propriété radius.

Gestion des événements

Lors de la gestion des événements dans React avec TypeScript, il est important de typer correctement l'objet événement. Utilisez le type d'événement approprié de l'espace de noms React.

const MyComponent: React.FC = () => {
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    console.log(event.target.value);
  };

  return (
    <input type="text" onChange={handleChange} />
  );
};

Dans cet exemple, React.ChangeEvent<HTMLInputElement> est utilisé pour typer l'objet événement pour un événement de changement sur un élément d'entrée. Cela donne accès à la propriété target, qui est un HTMLInputElement.

Structure du projet

Une structure de projet bien organisée est cruciale pour la maintenabilité et l'évolutivité. Voici une structure de projet suggérée pour une application React TypeScript :

src/
  ├── components/
  │   ├── MyComponent/
  │   │   ├── MyComponent.tsx
  │   │   ├── MyComponent.module.css
  │   │   └── index.ts
  ├── pages/
  │   ├── HomePage.tsx
  │   └── AboutPage.tsx
  ├── services/
  │   ├── api.ts
  │   └── auth.ts
  ├── types/
  │   ├── index.ts
  │   └── models.ts
  ├── utils/
  │   ├── helpers.ts
  │   └── constants.ts
  ├── App.tsx
  ├── index.tsx
  ├── react-app-env.d.ts
  └── tsconfig.json

Points clés :

Utilisation des Hooks avec TypeScript

Les Hooks React vous permettent d'utiliser l'état et d'autres fonctionnalités React dans les composants fonctionnels. TypeScript fonctionne parfaitement avec les Hooks, offrant une sécurité de type et une expérience de développeur améliorée.

useState

Comme montré précédemment, vous pouvez typer explicitement la variable d'état lors de l'utilisation de useState :

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  return (
    

Compteur : {count}

); };

useEffect

Lors de l'utilisation de useEffect, soyez attentif au tableau de dépendances. TypeScript peut vous aider à détecter les erreurs si vous oubliez d'inclure une dépendance utilisée dans l'effet.

import React, { useState, useEffect } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    document.title = `Compteur : ${count}`;
  }, [count]); // Ajoutez 'count' au tableau des dépendances

  return (
    

Compteur : {count}

); };

Si vous omettez count du tableau de dépendances, l'effet ne s'exécutera qu'une seule fois au montage du composant, et le titre du document ne sera pas mis à jour lorsque le compteur changera. TypeScript vous avertira de ce problème potentiel.

useContext

Lors de l'utilisation de useContext, vous devez fournir un type pour la valeur du contexte.

import React, { createContext, useContext } from 'react';

interface ThemeContextType {
  theme: string;
  toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

const ThemeProvider: React.FC = ({ children }) => {
  // Implémentez la logique du thème ici
  return (
     {} }}>
      {children}
    
  );
};

const MyComponent: React.FC = () => {
  const { theme, toggleTheme } = useContext(ThemeContext) as ThemeContextType;

  return (
    

Thème : {theme}

); }; export { ThemeProvider, MyComponent };

En fournissant un type pour la valeur du contexte, vous vous assurez que le hook useContext renvoie une valeur du bon type.

Tester les composants React TypeScript

Les tests sont une partie essentielle de la construction d'applications robustes. TypeScript améliore les tests en fournissant une sécurité de type et une couverture de code améliorée.

Tests unitaires

Utilisez des frameworks de test comme Jest et React Testing Library pour tester unitairement vos composants.

// MyComponent.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('rend le composant avec le nom correct', () => {
    render(<MyComponent name="John" />);
    expect(screen.getByText('Bonjour, John !')).toBeInTheDocument();
  });

  it('appelle le gestionnaire onClick lors du clic sur le bouton', () => {
    const onClick = jest.fn();
    render(<MyComponent name="John" onClick={onClick} />);
    fireEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

La vérification des types de TypeScript aide à détecter les erreurs dans vos tests, comme le passage de props incorrectes ou l'utilisation de gestionnaires d'événements erronés.

Tests d'intégration

Les tests d'intégration vérifient que différentes parties de votre application fonctionnent correctement ensemble. Utilisez des outils comme Cypress ou Playwright pour les tests de bout en bout.

Optimisation des performances

TypeScript peut également aider à l'optimisation des performances en détectant les goulots d'étranglement potentiels au début du processus de développement.

Mémorisation

Utilisez React.memo pour mémoriser les composants fonctionnels et éviter les rendus inutiles.

import React from 'react';

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ name }) => {
  console.log('Rendu de MyComponent');
  return (
    <p>Bonjour, {name} !</p>
  );
};

export default React.memo(MyComponent);

React.memo ne rendra le composant que si les props ont changé. Cela peut améliorer considérablement les performances, en particulier pour les composants complexes.

Fractionnement du code

Utilisez les importations dynamiques pour fractionner votre code en morceaux plus petits et les charger à la demande. Cela peut réduire le temps de chargement initial de votre application.

import React, { Suspense } from 'react';

const MyComponent = React.lazy(() => import('./MyComponent'));

const App: React.FC = () => {
  return (
    <Suspense fallback={
Chargement...
}> <MyComponent /> </Suspense> ); };

React.lazy vous permet d'importer dynamiquement des composants, qui ne sont chargés que lorsqu'ils sont nécessaires. Le composant Suspense fournit une interface utilisateur de secours pendant le chargement du composant.

Conclusion

L'utilisation de TypeScript avec React peut améliorer considérablement la qualité, la maintenabilité et l'évolutivité de vos applications web. En suivant ces bonnes pratiques, vous pouvez tirer parti de la puissance de TypeScript pour créer des applications robustes et performantes qui répondent aux besoins d'un public mondial. N'oubliez pas de vous concentrer sur des définitions de types claires, une organisation de projet bien structurée et des tests approfondis pour assurer le succès à long terme de vos projets.

Ressources supplémentaires