Mr Josselin A - TypeScript









JSX

Références

L'actualité

Librairie

L'information

Introduction

JSX est une syntaxe de type XML incorporable. Il est destiné à être transformé en JavaScript valide, bien que la sémantique de cette transformation soit spécifique à l'implémentation. JSX a gagné en popularité avec le framework React, mais a depuis vu d'autres implémentations. TypeScript prend en charge l'incorporation, la vérification de type et la compilation de JSX directement dans JavaScript.

Utilisation de base

Pour utiliser JSX, vous devez faire deux choses.

  • Nommez vos fichiers avec une extension .tsx
  • Activer l'option jsx

TypeScript est livré avec trois modes JSX : preserve, react, et react-native. Ces modes n'affectent que la phase d'émission, la vérification du type n'est pas affectée. Le mode preserve conservera le JSX comme partie de la sortie à consommer davantage par une autre étape de transformation (par exemple, Babel). De plus, la sortie aura une extension de fichier .jsx. Le mode react émettra React.createElement, il n'est pas nécessaire de passer par une transformation JSX avant utilisation et la sortie aura une extension de fichier .js. Le mode react-native équivaut preserve à conserver tous les fichiers JSX, mais la sortie aura plutôt une extension de fichier .js.
Mode Contribution Sortie Extension du fichier de sortie
preserve ‹div/› ‹div/› .jsx
react ‹div/› React.createElement("div") .js
react-native ‹div/› ‹div/› .js

Vous pouvez spécifier ce mode à l'aide de l'indicateur --jsx de ligne de commande ou de l'option correspondante dans votre fichier tsconfig.json.

Remarque : L'identifiant React est codé en dur. Vous devez donc rendre React disponible avec un "R" (majuscule).

L'opérateur as

Rappelez-vous comment écrire une assertion de type :

Ceci affirme que la variable bar a le type foo. étant donné que TypeScript utilise également les crochets angulaires pour les assertions de types, sa combinaison avec la syntaxe de JSX soulèverait certaines difficultés d'analyse. En conséquence, TypeScript interdit les assertions de type à crochets angulaires dans les fichiers .tsx.

étant donné que la syntaxe ci-dessus ne peut pas être utilisé dans les fichiers .tsx, un opérateur d'assertion de type alternatif doit être utilisé : as. L'exemple peut facilement être réécrit avec l'opérateur as.

L'opérateur as est disponible dans les deux fichiers .ts et .tsx, et son comportement est identique au style d'assertion de type à crochet.

Vérification de type

Pour comprendre la vérification de type avec JSX, vous devez d'abord comprendre la différence entre les éléments intrinsèques et les éléments basés sur des valeurs. Si vous utilisez une expression JSX ‹expr /›, vous pouvez faire référence à un élément intrinsèque de l'environnement (par exemple, un environnement DOM div ou span) ou à un composant personnalisé que vous avez créé. Ceci est important pour deux raisons :

  • Pour React, les éléments intrinsèques sont émis sous forme de chaînes ( React.createElement("div") ), alors qu'un composant que vous avez créé ne l'est pas ( React.createElement(MyComponent) ).
  • Les types d'attributs transmis dans l'élément JSX doivent être recherchés différemment. Les attributs d'éléments intrinsèques doivent être connus intrinsèquement, alors que les composants voudront probablement spécifier leur propre ensemble d'attributs.

TypeScript utilise la même convention que React pour les distinguer. Un élément intrinsèque commence toujours par une lettre minuscule et un élément basé sur une valeur commence toujours par une lettre majuscule.

éléments intrinsèques

Les éléments intrinsèques sont recherchés sur l'interface spéciale JSX.IntrinsicElements. Par défaut, si cette interface n'est pas spécifiée, tout se passe bien et les éléments intrinsèques ne seront pas vérifiés. Cependant, si cette interface est présente, le nom de l'élément intrinsèque est alors considéré comme une propriété de l'interface JSX.IntrinsicElements.

Par exemple :

Dans l'exemple ci-dessus, ‹foo /› cela fonctionnera bien, mais ‹bar /› entraînera une erreur car cela n'a pas été spécifié JSX.IntrinsicElements.

Remarque : Vous pouvez également spécifier un indexeur de chaîne fourre-tout JSX.IntrinsicElements comme suit :

éléments de valeur

Les éléments basés sur la valeur sont simplement recherchés par les identificateurs qui sont dans la portée.

Il existe deux manières de définir un élément basé sur une valeur :
  • Composant fonctionnel sans état (SFC)
  • Composant de classe
Etant donné que ces deux types d'éléments basés sur la valeur ne peuvent pas être distingués dans une expression JSX, TypeScript essaie d'abord de résoudre l'expression en tant que composant fonctionnel sans état à l'aide de la résolution de surcharge. Si le processus aboutit, TypeScript finit de résoudre l'expression en sa déclaration. Si la valeur ne parvient pas à résoudre en tant que SFC, TypeScript essaiera de la résoudre en tant que composant de classe. Si cela échoue, TypeScript signalera une erreur.

Composant fonctionnel sans état

Comme son nom l'indique, le composant est défini comme une fonction JavaScript dont le premier argument est un objet props. TypeScript impose que son type de retour doit être assignable JSX.Element.

Puisqu'une SFC est simplement une fonction JavaScript, les surcharges de fonctions peuvent également être utilisées ici:

Composant de classe

Il est possible de définir le type d'un composant de classe. Cependant, pour ce faire, il est préférable de comprendre deux nouveaux termes : le type de classe d'élément et le type d'instance d'élément.

étant donné ‹Expr /›, le type de classe d'élément est le type de Expr. Ainsi, dans l'exemple ci-dessus, si MyComponent était une classe ES6, le type de classe serait le constructeur et la statique de cette classe. Si MyComponent était une fonction d'usine, le type de classe serait cette fonction.

Une fois le type de classe établi, le type d'instance est déterminé par l'union des types de retour de la construction ou des signatures d'appel du type de classe (selon le cas). De même, dans le cas d'une classe ES6, le type d'instance serait le type d'une instance de cette classe et, dans le cas d'une fonction factory, ce serait le type de la valeur renvoyée par la fonction.

Le type d'instance d'élément est intéressant car il doit être assignable à JSX.ElementClass sinon cela entraînera une erreur. Par défaut JSX.ElementClass est {}, mais il peut être augmentée pour limiter l'utilisation de JSX aux seuls types qui sont conformes à l'interface appropriée.

Vérification du type d'attribut

La première étape pour taper les attributs de vérification consiste à déterminer le type des attributs d'élément. Ceci est légèrement différent entre les éléments intrinsèques et les éléments basés sur la valeur.

Pour les éléments intrinsèques, c'est le type de la propriété sur JSX.IntrinsicElements

Pour les éléments basés sur la valeur, c'est un peu plus complexe. Elle est déterminée par le type d'une propriété du type d'instance d'élément précédemment déterminé. La propriété à utiliser est déterminée par JSX.ElementAttributesProperty. Il devrait être déclaré avec une seule propriété. Le nom de cette propriété est ensuite utilisé. A partir de TypeScript 2.8, si JSX.ElementAttributesProperty n'est pas fourni, le type du premier paramètre du constructeur de l'élément de classe ou l'appel de SFC sera utilisé à la place.

Le type d'attribut d'élément est utilisé pour vérifier les attributs dans le fichier JSX. Les propriétés facultatives et obligatoires sont prises en charge.

Remarque: Si un nom d'attribut n'est pas un identifiant JS valide (comme un data-* attribut), il n'est pas considéré comme une erreur s'il n'est pas trouvé dans le type d'attribut d'élément.

En outre, l'interface JSX.IntrinsicAttributes peut être utilisée pour spécifier des propriétés supplémentaires utilisées par le framework JSX qui ne sont généralement pas utilisées par les propriétés ou les arguments des composants, par exemple la clé dans React. En outre, le type générique JSX.IntrinsicClassAttributes‹T› peut également être utilisé pour spécifier le même type d'attributs supplémentaires uniquement pour les composants de classe (et non les SFC). Dans ce type, le paramètre générique correspond au type d'instance de classe. Dans React, ceci est utilisé pour autoriser l'attribut ref de type Ref‹T›.

En règle générale, toutes les propriétés de ces interfaces doivent être facultatives, sauf si vous souhaitez que les utilisateurs de votre infrastructure JSX doivent fournir un attribut pour chaque balise.

L'opérateur de diffusion travaille également:

Vérification du type d'enfants

Dans TypeScript 2.3, TypeScript a introduit la vérification de type des enfants. children est une propriété spéciale dans un type d'attribut d'élément dans lequel les enfants JSXExpression sont supposés être insérés dans les attributs. Semblable à la façon dont TypeScript utilise JSX.ElementAttributesProperty pour déterminer le nom des accessoires , TypeScript utilise JSX.ElementChildrenAttribute pour déterminer le nom des enfants contenus dans ces accessoires. JSX.ElementChildrenAttribute doit être déclaré avec une seule propriété.


Vous pouvez spécifier le type d'enfants comme n'importe quel autre attribut. Cela remplacera le type par défaut à partir de, par exemple les typages React si vous les utilisez.


Le type de résultat JSX

Par défaut, le résultat d'une expression JSX est tapé comme any. Vous pouvez personnaliser le type en spécifiant l'interface JSX.Element. Cependant, il n'est pas possible de récupérer des informations de type sur l'élément, les attributs ou les enfants du JSX à partir de cette interface. C'est une boîte noire.

Incorporation d'expressions

JSX vous permet d'incorporer des expressions entre les balises en les entourant d'accolades ({ }).

Le code ci-dessus entraînera une erreur car vous ne pouvez pas diviser une chaîne par un nombre. La sortie, lorsque vous utilisez l'option preserve, ressemble à ceci :


Réagir à l'intégration

Pour utiliser JSX avec React, vous devez utiliser les typages React. Ces typages définissent l'espace de noms JSX à utiliser avec React.


Fonctions d'usine

La fonction d'usine exacte utilisée par l'option jsx: react du compilateur est configurable. Il peut être défini à l'aide de l'option jsxFactory de ligne de commande ou d'un @jsx de commentaire intégré pour le définir fichier par fichier. Par exemple, si vous définissez jsxFactory sur createElement, ‹div /› émettra en tant que createElement("div") au lieu de React.createElement("div").

La version de pragma de commentaire peut être utilisée comme suit (dans TypeScript 2.8) :

émet comme :

La fabrique choisie affectera également l'emplacement de l'espace de noms JSX (pour les informations de contrôle de type) avant de revenir à l'espace global. Si la fabrique est définie comme React.createElement(valeur par défaut), le compilateur vérifiera React.JSX avant de rechercher une variable globale JSX. Si la fabrique est définie comme h, elle recherchera h.JSX avant une globale JSX.