Cours JavaScript et React · Module 12: React et TypeScript

Typer les composants fonctionnels

5 min de lecture
Dans cette leçon3

Tu as construit un module de vaisseau, tu l'as connecté au reste, et une semaine plus tard un membre d'équipage lui passe un nombre là où il attendait du texte. Personne ne l'a remarqué, car le composant n'avait aucun manuel d'utilisation. En React, chaque composant est une fonction. TypeScript nous permet de définir précisément ce que cette fonction accepte (les props) et ce qu'elle renvoie (le JSX). C'est comme le manuel d'utilisation de chaque module d'un vaisseau spatial.

React.FC vs typage explicite

Il existe deux façons populaires de typer les composants fonctionnels en React. Tu rencontreras les deux dans le code des autres, alors il vaut la peine de comprendre chacune avant de choisir la tienne.

Méthode 1 : React.FC (Function Component)

React.FC (abréviation de React.FunctionComponent) est un type générique : tu passes le type des props entre chevrons et il décrit toute la fonction du composant. Tu l'attaches à la constante, pas au paramètre. Pour utiliser le nom React.FC, il faut importer React (ou seulement le type FC).

1import React from 'react';
2
3// React.FC décrit toute la fonction du composant (props + type de retour)
4const StarInfo: React.FC = () => {
5  return <p>Informations sur l'étoile</p>;
6};

Sans paramètre générique, React.FC désigne un composant sans props. Quand il faut des props, on les décrit d'abord avec une interface StarProps, puis on passe cette interface entre chevrons :

1// React.FC avec props
2interface StarProps {
3  name: string;
4  brightness: number;
5}
6
7const StarCard: React.FC<StarProps> = ({ name, brightness }) => {
8  return (
9    <div>
10      <h3>{name}</h3>
11      <p>Brightness: {brightness}</p>
12    </div>
13  );
14};

TypeScript sait maintenant que name est une chaîne et brightness un nombre, même si la déstructuration elle-même ne contient aucun type - ils viennent de l'annotation sur la constante StarCard.

Méthode 2 : typage explicite (recommandé)

La deuxième méthode type directement le paramètre de la fonction, exactement comme dans n'importe quelle fonction TypeScript. Tu peux écrire le type de retour React.JSX.Element, c'est-à-dire "un élément JSX".

1// Typage explicite - plus transparent et flexible
2interface StarProps {
3  name: string;
4  brightness: number;
5}
6
7function StarCard({ name, brightness }: StarProps): React.JSX.Element {
8  return (
9    <div>
10      <h3>{name}</h3>
11      <p>Brightness: {brightness}</p>
12    </div>
13  );
14}

La même notation fonctionne dans une fonction fléchée - le type des props reste sur le paramètre, pas sur la constante :

1// Ou comme une fonction fléchée
2const StarCardArrow = ({ name, brightness }: StarProps): React.JSX.Element => {
3  return (
4    <div>
5      <h3>{name}</h3>
6      <p>Brightness: {brightness}</p>
7    </div>
8  );
9};

Le JSX à l'intérieur n'a pas changé d'un seul caractère par rapport à la méthode 1. La seule différence est l'endroit où se trouve l'information de type.

Pourquoi le typage explicite est-il recommandé ?

La communauté React s'est largement éloignée de React.FC pour plusieurs raisons :

  1. React.FC ajoutait autrefois children - jusqu'à @types/react 17, chaque composant React.FC "acceptait" children, même s'il ne les utilisait pas. Depuis @types/react 18 ce n'est plus le cas, mais beaucoup d'anciens articles le répètent encore
  2. Le typage explicite est plus lisible - on voit exactement ce que le composant accepte
  3. Meilleure compatibilité - il fonctionne de la même façon avec function et les fonctions fléchées, ainsi qu'avec les composants génériques, que React.FC ne sait pas exprimer

Regarde ce qui se passe quand tu essaies d'utiliser children avec les deux approches dans le React moderne :

1// React.FC - depuis @types/react 18, children n'est PAS ajouté automatiquement
2const Badge: React.FC<{ label: string }> = ({ label, children }) => {
3  return <span>{label}{children}</span>; // ERREUR : la propriété 'children' n'existe pas
4};
5
6// Typage explicite - children doit être ajouté explicitement
7interface BadgeProps {
8  label: string;
9}
10
11function Badge({ label }: BadgeProps): React.JSX.Element {
12  return <span>{label}</span>; // pas de children, car il n'est pas dans les props
13}

Dans les deux cas, si un composant doit accepter children, tu dois les ajouter au type des props - nous le ferons dans la prochaine leçon. Mon conseil : écris les types explicitement sur le paramètre. C'est plus court, plus clair et conforme aux exemples de react.dev.

Type de retour d'un composant

Un composant React peut renvoyer différentes choses : un élément JSX, du texte, un nombre, ou null quand il n'y a rien à afficher. Chaque possibilité a son propre type :

1// React.JSX.Element - le plus couramment utilisé
2function Planet(): React.JSX.Element {
3  return <div>Mars</div>;
4}
5
6// React.ReactElement - type plus général d'élément React
7function Planet(): React.ReactElement {
8  return <div>Mars</div>;
9}

Une correction importante par rapport aux anciens tutoriels : écrire JSX.Element sans préfixe reposait sur l'espace de noms global JSX, qui a été supprimé des types de React 19. Écris React.JSX.Element - cela fonctionne avec React 18 et 19. Si un composant peut renvoyer null ou du texte, utilise le type le plus large :

1// React.ReactNode - le plus flexible (JSX, string, number, null)
2function MaybeContent(): React.ReactNode {
3  return null; // peut retourner null
4}
5
6// En pratique, on omet le plus souvent le type de retour
7// TypeScript le déduit automatiquement
8function Planet() {
9  return <div>Mars</div>; // TypeScript sait que c'est un React.JSX.Element
10}

Un composant qui renvoie React.ReactNode peut être utilisé en JSX depuis TypeScript 5.1. Au quotidien, tu omets généralement le type de retour et laisses le compilateur le déduire - ce sont les props typées qui protègent vraiment ton vaisseau.

Entraîne-toi aux deux styles dans l'éditeur. Dans la prochaine leçon, nous enrichirons l'interface des props avec des champs optionnels et children.

Code de cette leçon : App.tsx
1import React from 'react';
2
3// Interface des props
4interface CrewMemberProps {
5  name: string;
6  rank: string;
7  specialization: string;
8  yearsInSpace: number;
9}
10
11// Méthode 1 : React.FC (Function Component)
12const CrewBadgeFC: React.FC<CrewMemberProps> = ({ name, rank, specialization, yearsInSpace }) => {
13  return (
14    <div className="badge-card">
15      <div className="badge-header">FC</div>
16      <h3>{name}</h3>
17      <p className="rank">{rank}</p>
18      <p>Spécialisation : {specialization}</p>
19      <p>Années dans l'espace : {yearsInSpace}</p>
20    </div>
21  );
22};
23
24// Méthode 2 : typage explicite (recommandé)
25function CrewBadgeExplicit({ name, rank, specialization, yearsInSpace }: CrewMemberProps): JSX.Element {
26  return (
27    <div className="badge-card">
28      <div className="badge-header">Explicit</div>
29      <h3>{name}</h3>
30      <p className="rank">{rank}</p>
31      <p>Spécialisation : {specialization}</p>
32      <p>Années dans l'espace : {yearsInSpace}</p>
33    </div>
34  );
35}
36
37// Méthode 3 : fonction fléchée avec type explicite
38const CrewBadgeArrow = ({ name, rank, specialization, yearsInSpace }: CrewMemberProps): JSX.Element => {
39  return (
40    <div className="badge-card">
41      <div className="badge-header">Arrow</div>
42      <h3>{name}</h3>
43      <p className="rank">{rank}</p>
44      <p>Spécialisation : {specialization}</p>
45      <p>Années dans l'espace : {yearsInSpace}</p>
46    </div>
47  );
48};
49
50function App() {
51  const member: CrewMemberProps = {
52    name: "Nova",
53    rank: "Capitaine",
54    specialization: "Navigation",
55    yearsInSpace: 15
56  };
57
58  return (
59    <div className="app">
60      <h1>Façons de typer les composants</h1>
61      <div className="cards">
62        <CrewBadgeFC {...member} />
63        <CrewBadgeExplicit {...member} />
64        <CrewBadgeArrow {...member} />
65      </div>
66      <p className="note">Les trois méthodes donnent le même résultat. La méthode avec typage explicite (Explicit) est recommandée.</p>
67    </div>
68  );
69}
70
71export default App;

Retiens : le type des props est le manuel d'utilisation du module - colle-le sur le paramètre, et chaque membre d'équipage sait comment le brancher.

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Quelle extension de fichier est utilisée pour les composants React écrits en TypeScript ?

  2. 2. Quelle approche pour typer les composants fonctionnels est actuellement recommandée par la communauté React ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Typage de base des interfaces et des composants

  • Clique dans l'ordre

    Ordonne la syntaxe de la définition d'une interface en TypeScript :

Articles utiles