Définition de TypeScript pour les projets React modernes à l'aide de Webpack

Publié: 2022-03-10
Résumé rapide ↬ Cet article présente Typescript, un exposant de JavaScript qui présente la fonctionnalité de type statique pour repérer les erreurs courantes en tant que codes de développeurs, ce qui améliore les performances et se traduit donc par des applications d'entreprise robustes. Vous apprendrez également à configurer efficacement TypeScript dans un projet React pendant que nous construisons une application de sélection d'épisodes Money Heist, en explorant TypeScript, des crochets React tels que useReducer, useContext et Reach Router.

En cette ère de développement de logiciels, JavaScript peut être utilisé pour développer presque n'importe quel type d'application. Cependant, le fait que JavaScript soit typé dynamiquement pourrait être une préoccupation pour la plupart des grandes entreprises, en raison de sa fonction de vérification de type lâche.

Heureusement, nous n'avons pas à attendre que le comité technique Ecma 39 introduise un système de type statique dans JavaScript. Nous pouvons utiliser TypeScript à la place.

JavaScript, étant typé dynamiquement, n'est pas conscient du type de données d'une variable tant que cette variable n'est pas instanciée au moment de l'exécution. Les développeurs qui écrivent de gros programmes logiciels peuvent avoir tendance à réaffecter une variable, déclarée précédemment, à une valeur d'un type différent, sans avertissement ni problème, ce qui entraîne des bogues souvent ignorés.

Dans ce didacticiel, nous apprendrons ce qu'est TypeScript et comment l'utiliser dans un projet React. À la fin, nous aurons construit un projet consistant en une application de sélection d'épisodes pour l'émission télévisée Money Heist , utilisant TypeScript et les crochets actuels de type React ( useState , useEffect , useReducer , useContext ). Avec ces connaissances, vous pouvez continuer à expérimenter TypeScript dans vos propres projets.

Cet article n'est pas une introduction à TypeScript. Par conséquent, nous n'aborderons pas la syntaxe de base de TypeScript et JavaScript. Cependant, vous n'avez pas besoin d'être un expert dans l'une de ces langues pour suivre, car nous essaierons de suivre le principe KISS (restez simple, stupide).

Plus après saut! Continuez à lire ci-dessous ↓

Qu'est-ce que TypeScript ?

En 2019, TypeScript a été classé septième langage le plus utilisé et cinquième langage à la croissance la plus rapide sur GitHub. Mais qu'est-ce que TypeScript exactement ?

Selon la documentation officielle, TypeScript est un sur-ensemble typé de JavaScript qui se compile en JavaScript brut. Il est développé et maintenu par Microsoft et la communauté open source.

"Superset" dans ce contexte signifie que le langage contient toutes les caractéristiques et fonctionnalités de JavaScript et plus encore. TypeScript est un langage de script typé.

Il offre aux développeurs plus de contrôle sur leur base de code via ses annotations de type, ses classes et son interface, évitant aux développeurs d'avoir à corriger manuellement des bogues gênants dans la console.

TypeScript n'a pas été créé pour modifier JavaScript. Au lieu de cela, il développe JavaScript avec de nouvelles fonctionnalités précieuses. Tout programme écrit en JavaScript brut fonctionnera également comme prévu dans TypeScript, y compris les applications mobiles multiplateformes et les back-ends dans Node.js.

Cela signifie que vous pouvez également écrire des applications React en TypeScript, comme nous le ferons dans ce didacticiel.

Pourquoi TypeScript ?

Peut-être n'êtes-vous pas convaincu d'embrasser la bonté de TypeScript. Considérons quelques-uns de ses avantages.

Moins de bogues

Nous ne pouvons pas éliminer tous les bogues de notre code, mais nous pouvons les réduire. TypeScript vérifie les types au moment de la compilation et génère des erreurs si le type de variable change.

Pouvoir trouver ces erreurs évidentes mais fréquentes aussi tôt facilite grandement la gestion de votre code avec les types.

La refactorisation est plus facile

Vous voulez probablement souvent refactoriser pas mal de choses, mais parce qu'elles touchent tellement d'autres codes et beaucoup d'autres fichiers, vous hésitez à les modifier.

Dans TypeScript, de telles choses peuvent souvent être refactorisées d'un simple clic sur la commande "Renommer le symbole" dans votre environnement de développement intégré (IDE).

Renommer l'application en expApp ( Grand aperçu )

Dans un langage à typage dynamique tel que JavaScript, la seule façon de refactoriser plusieurs fichiers en même temps est d'utiliser la fonction traditionnelle de « rechercher et remplacer » à l'aide d'expressions régulières (RegExp).

Dans un langage à typage statique tel que TypeScript, "rechercher et remplacer" n'est plus nécessaire. Avec les commandes IDE telles que "Rechercher toutes les occurrences" et "Renommer le symbole", vous pouvez voir toutes les occurrences dans l'application de la fonction, de la classe ou de la propriété donnée d'une interface d'objet.

TypeScript vous aidera à trouver toutes les instances du bit refactorisé, à le renommer et à vous alerter avec une erreur de compilation au cas où votre code présenterait des incompatibilités de type après le refactoring.

TypeScript a encore plus d'avantages que ce que nous avons couvert ici.

Inconvénients de TypeScript

TypeScript n'est sûrement pas sans inconvénients, même compte tenu des fonctionnalités prometteuses soulignées ci-dessus.

Un faux sentiment de sécurité

La fonctionnalité de vérification de type de TypeScript crée souvent un faux sentiment de sécurité parmi les développeurs. La vérification de type nous avertit en effet lorsque quelque chose ne va pas avec notre code. Cependant, les types statiques ne réduisent pas la densité globale des bogues.

Par conséquent, la force de votre programme dépendra de votre utilisation de TypeScript, car les types sont écrits par le développeur et ne sont pas vérifiés au moment de l'exécution.

Si vous cherchez à TypeScript pour réduire vos bogues, veuillez plutôt envisager le développement piloté par les tests.

Système de saisie compliqué

Le système de saisie, bien qu'il soit un excellent outil à bien des égards, peut parfois être un peu compliqué. Cet inconvénient vient du fait qu'il est entièrement interopérable avec JavaScript, ce qui laisse encore plus de place à la complication.

Cependant, TypeScript est toujours JavaScript, il est donc important de comprendre JavaScript.

Quand utiliser TypeScript ?

Je vous conseille d'utiliser TypeScript dans les cas suivants :

  • Si vous cherchez à créer une application qui sera maintenue sur une longue période , je vous recommande fortement de commencer par TypeScript, car il favorise l'auto-documentation du code, aidant ainsi les autres développeurs à comprendre facilement votre code lorsqu'ils rejoignent votre base de code. .
  • Si vous avez besoin de créer une bibliothèque , envisagez de l'écrire en TypeScript. Cela aidera les éditeurs de code à suggérer les types appropriés aux développeurs qui utilisent votre bibliothèque.

Dans les dernières sections, nous avons équilibré les avantages et les inconvénients de TypeScript. Passons à l'affaire du jour : configurer TypeScript dans un projet React moderne .

Commencer

Il existe plusieurs façons de configurer TypeScript dans un projet React. Dans ce didacticiel, nous n'en couvrirons que deux.

Méthode 1 : créer une application React + TypeScript

Il y a environ deux ans, l'équipe React a publié Create React App 2.1, avec prise en charge de TypeScript. Ainsi, vous n'aurez peut-être jamais à faire de gros travaux pour intégrer TypeScript dans votre projet.

Annonce de TypeScript dans l'application Create React ( Grand aperçu )

Pour démarrer un nouveau projet Create React App, vous pouvez exécuter ceci…

 npx create-react-app my-app --folder-name

… ou ca:

 yarn create react-app my-app --folder-name

Pour ajouter TypeScript à un projet Create React App, installez-le d'abord avec ses @types respectifs :

 npm install --save typescript @types/node @types/react @types/react-dom @types/jest

… ou:

 yarn add typescript @types/node @types/react @types/react-dom @types/jest

Ensuite, renommez les fichiers (par exemple, index.js en index.tsx ), et redémarrez votre serveur de développement !

C'était rapide, n'est-ce pas ?

Méthode 2 : configurer TypeScript avec Webpack

Webpack est un bundler de modules statiques pour les applications JavaScript. Il prend tout le code de votre application et le rend utilisable dans un navigateur Web. Les modules sont des morceaux de code réutilisables construits à partir des styles JavaScript, node_modules , images et CSS de votre application, qui sont emballés pour être facilement utilisés sur votre site Web.

Créer un nouveau projet

Commençons par créer un nouveau répertoire pour notre projet :

 mkdir react-webpack cd react-webpack

Nous allons utiliser npm pour initialiser notre projet :

 npm init -y

La commande ci-dessus générera un fichier package.json avec certaines valeurs par défaut. Ajoutons également quelques dépendances pour webpack, TypeScript et certains modules spécifiques à React.

Installation de packages

Enfin, nous devons installer les packages nécessaires. Ouvrez votre interface de ligne de commande (CLI) et exécutez ceci :

 #Installing devDependencies npm install --save-dev @types/react @types/react-dom awesome-typescript-loader css-loader html-webpack-plugin mini-css-extract-plugin source-map-loader typescript webpack webpack-cli webpack-dev-server #installing Dependencies npm install react react-dom

Ajoutons également manuellement quelques fichiers et dossiers différents sous notre dossier react-webpack :

  1. Ajoutez webpack.config.js pour ajouter des configurations liées au webpack.
  2. Ajoutez tsconfig.json pour toutes nos configurations TypeScript.
  3. Ajoutez un nouveau répertoire, src .
  4. Créez un nouveau répertoire, components , dans le dossier src .
  5. Enfin, ajoutez index.html , App.tsx et index.tsx dans le dossier des components .

Structure du projet

Ainsi, notre structure de dossiers ressemblera à ceci :

 ├── package.json ├── package-lock.json ├── tsconfig.json ├── webpack.config.js ├── .gitignore └── src └──components ├── App.tsx ├── index.tsx ├── index.html

Commencez à ajouter du code

Nous allons commencer par index.html :

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>React-Webpack Setup</title> </head> <body> <div></div> </body> </html>

Cela créera le HTML, avec un div vide avec un ID de output .

Ajoutons le code à notre composant React App.tsx :

 import * as React from "react"; export interface HelloWorldProps { userName: string; lang: string; } export const App = (props: HelloWorldProps) => ( <h1> Hi {props.userName} from React! Welcome to {props.lang}! </h1> );

Nous avons créé un objet d'interface et l'avons nommé HelloWorldProps , avec userName et lang ayant un type de string .

Nous avons transmis props à notre composant App et l'avons exporté.

Maintenant, mettons à jour le code dans index.tsx :

 import * as React from "react"; import * as ReactDOM from "react-dom"; import { App } from "./App"; ReactDOM.render( <App userName="Beveloper" lang="TypeScript" />, document.getElementById("output") );

Nous venons d'importer le composant App dans index.tsx . Lorsque webpack voit un fichier avec l'extension .ts ou .tsx , il transpile ce fichier à l'aide de la bibliothèque awesome-typescript-loader.

Configuration TypeScript

Nous ajouterons ensuite une configuration à tsconfig.json :

 { "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "src/components/index.tsx" ] }

Regardons également les différentes options que nous avons ajoutées à tsconfig.json :

  • compilerOptions Représente les différentes options du compilateur.
  • jsx:react Ajoute la prise en charge de JSX dans les fichiers .tsx .
  • lib Ajoute une liste de fichiers de bibliothèque à la compilation (par exemple, l'utilisation es2015 nous permet d'utiliser la syntaxe ECMAScript 6).
  • module Génère le code du module.
  • noImplicitAny des erreurs pour les déclarations avec un type any implicite.
  • outDir Représente le répertoire de sortie.
  • sourceMap Génère un fichier .map , qui peut être très utile pour déboguer l'application.
  • target Représente la version ECMAScript cible vers laquelle transpiler notre code (nous pouvons ajouter une version en fonction des exigences spécifiques de notre navigateur).
  • include Utilisé pour spécifier la liste de fichiers à inclure.

Configuration Webpack

Ajoutons une configuration de webpack à webpack.config.js .

 const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/components/index.tsx", target: "web", mode: "development", output: { path: path.resolve(\__dirname, "build"), filename: "bundle.js", }, resolve: { extensions: [".js", ".jsx", ".json", ".ts", ".tsx"], }, module: { rules: [ { test: /\.(ts|tsx)$/, loader: "awesome-typescript-loader", }, { enforce: "pre", test: /\.js$/, loader: "source-map-loader", }, { test: /\.css$/, loader: "css-loader", }, ], }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(\__dirname, "src", "components", "index.html"), }), new MiniCssExtractPlugin({ filename: "./src/yourfile.css", }), ], };

Regardons les différentes options que nous avons ajoutées à webpack.config.js :

  • entry Ceci spécifie le point d'entrée pour notre application. Il peut s'agir d'un fichier unique ou d'un tableau de fichiers que nous souhaitons inclure dans notre build.
  • output Ceci contient la configuration de sortie. L'application examine cela lorsqu'elle essaie de sortir du code groupé de notre projet sur le disque. Le chemin représente le répertoire de sortie pour le code à sortir, et le nom du fichier représente le nom du fichier pour le même. Il est généralement nommé bundle.js .
  • resolve Webpack examine cet attribut pour décider de regrouper ou d'ignorer le fichier. Ainsi, dans notre projet, webpack considérera les fichiers avec les extensions .js , .jsx , .json , .ts et .tsx pour le regroupement.
  • module Nous pouvons permettre à webpack de charger un fichier particulier à la demande de l'application, à l'aide de chargeurs. Il prend un objet rules qui spécifie que :
    • tout fichier qui se termine par l'extension .tsx ou .ts doit utiliser awesome-typescript-loader pour être chargé ;
    • les fichiers qui se terminent par l'extension .js doivent être chargés avec source-map-loader ;
    • les fichiers qui se terminent par l' .css doivent être chargés avec css-loader .
  • plugins Webpack a ses propres limites, et il fournit des plugins pour les surmonter et étendre ses capacités. Par exemple, html-webpack-plugin crée un fichier de modèle qui est rendu au navigateur à partir du fichier index.html dans le répertoire ./src/component/index.html .

MiniCssExtractPlugin rend le fichier CSS parent de l'application.

Ajout de scripts à package.json

Nous pouvons ajouter différents scripts pour créer des applications React dans notre fichier package.json :

 "scripts": { "start": "webpack-dev-server --open", "build": "webpack" },

Maintenant, exécutez npm start dans votre CLI. Si tout s'est bien passé, vous devriez voir ceci :

Sortie de configuration de React-Webpack ( Grand aperçu )

Si vous avez un talent pour le webpack, clonez le référentiel pour cette configuration et utilisez-le dans vos projets.

Création de fichiers

Créez un dossier src et un fichier index.tsx . Ce sera le fichier de base qui rend React.

Maintenant, si nous npm start , il exécutera notre serveur et ouvrira un nouvel onglet. L'exécution npm run build créera un pack Web pour la production et créera un dossier de construction pour nous.

Nous avons vu comment configurer TypeScript à partir de zéro en utilisant la méthode de configuration Create React App et webpack.

L'un des moyens les plus rapides de maîtriser pleinement TypeScript consiste à convertir l'un de vos projets Vanilla React existants en TypeScript. Malheureusement, l'adoption progressive de TypeScript dans un projet vanilla React existant est stressante car elle implique d'éjecter ou de renommer tous les fichiers, ce qui entraînerait des conflits et une demande d'extraction géante si le projet appartenait à une grande équipe.

Ensuite, nous verrons comment migrer facilement un projet React vers TypeScript.

Migrer une application Create React existante vers TypeScript

Pour rendre ce processus plus gérable, nous le décomposerons en étapes, ce qui nous permettra de migrer en morceaux individuels. Voici les étapes que nous allons suivre pour migrer notre projet :

  1. Ajoutez TypeScript et les types.
  2. Ajoutez tsconfig.json .
  3. Commencer petit.
  4. Renommez l'extension des fichiers en .tsx .

1. Ajouter TypeScript au projet

Tout d'abord, nous devrons ajouter TypeScript à notre projet. En supposant que votre projet React a été démarré avec Create React App, nous pouvons exécuter ce qui suit :

 # Using npm npm install --save typescript @types/node @types/react @types/react-dom @types/jest # Using Yarn yarn add typescript @types/node @types/react @types/react-dom @types/jest

Notez que nous n'avons encore rien changé à TypeScript. Si nous exécutons la commande pour démarrer le projet localement ( npm start ou yarn start ), rien ne change. Si c'est le cas, alors super ! Nous sommes prêts pour la prochaine étape.

2. Ajoutez le fichier tsconfig.json

Avant de profiter de TypeScript, nous devons le configurer via le fichier tsconfig.json . Le moyen le plus simple de commencer est d'en échafauder un à l'aide de cette commande :

 npx tsc --init

Cela nous donne quelques bases, avec beaucoup de code commenté. Maintenant, remplacez tout le code dans tsconfig.json par ceci :

 { "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "./src/**/**/\*" ] }

Configuration TypeScript

Regardons également les différentes options que nous avons ajoutées à tsconfig.json :

  • compilerOptions Représente les différentes options du compilateur.
    • target Traduit les nouvelles constructions JavaScript vers une version plus ancienne, comme ECMAScript 5.
    • lib Ajoute une liste de fichiers de bibliothèque à la compilation (par exemple, l'utilisation de es2015 nous permet d'utiliser la syntaxe ECMAScript 6).
    • jsx:react Ajoute la prise en charge de JSX dans les fichiers .tsx .
    • lib Ajoute une liste de fichiers de bibliothèque à la compilation (par exemple, l'utilisation de es2015 nous permet d'utiliser la syntaxe ECMAScript 6).
    • module Génère le code du module.
    • noImplicitAny Utilisé pour générer des erreurs pour les déclarations avec un type any implicite.
    • outDir Représente le répertoire de sortie.
    • sourceMap Génère un fichier .map , qui peut être très utile pour déboguer notre application.
    • include Utilisé pour spécifier la liste de fichiers à inclure.

Les options de configuration varient en fonction de la demande d'un projet. Vous devrez peut-être consulter la feuille de calcul des options TypeScript pour déterminer ce qui conviendrait à votre projet.

Nous avons seulement pris les mesures nécessaires pour que les choses soient prêtes. Notre prochaine étape consiste à migrer un fichier vers TypeScript.

3. Commencez avec un composant simple

Profitez de la capacité de TypeScript à être progressivement adopté. Allez un fichier à la fois à votre propre rythme. Faites ce qui a du sens pour vous et votre équipe. N'essayez pas de tout aborder d'un coup.

Pour convertir correctement cela, nous devons faire deux choses :

  1. Modifiez l'extension de fichier en .tsx .
  2. Ajoutez l'annotation de type (ce qui nécessiterait des connaissances en TypeScript).

4.Renommer les extensions de fichier en .tsx

Dans une grande base de code, il peut sembler fatigant de renommer les fichiers individuellement.

Renommer plusieurs fichiers sur macOS

Renommer plusieurs fichiers peut être une perte de temps. Voici comment vous pouvez le faire sur un Mac. Faites un clic droit (ou Ctrl + clic, ou cliquez avec deux doigts simultanément sur le trackpad si vous utilisez un MacBook) sur le dossier contenant les fichiers que vous souhaitez renommer. Ensuite, cliquez sur "Révéler dans le Finder". Dans le Finder, sélectionnez tous les fichiers que vous souhaitez renommer. Cliquez avec le bouton droit sur les fichiers sélectionnés et choisissez "Renommer les éléments X...". Ensuite, vous verrez quelque chose comme ceci :

Renommer des fichiers sur un Mac ( Grand aperçu )

Insérez la chaîne que vous souhaitez rechercher et la chaîne par laquelle vous souhaitez remplacer cette chaîne trouvée, puis appuyez sur "Renommer". Terminé.

Renommer plusieurs fichiers sous Windows

Renommer plusieurs fichiers sous Windows dépasse le cadre de ce didacticiel, mais un guide complet est disponible. Vous obtiendrez généralement des erreurs après avoir renommé les fichiers ; il vous suffit d'ajouter les annotations de type. Vous pouvez approfondir cela dans la documentation.

Nous avons expliqué comment configurer TypeScript dans une application React. Maintenant, construisons une application de sélection d'épisodes pour Money Heist en utilisant TypeScript.

Nous ne couvrirons pas les types de base de TypeScript. Il est nécessaire de parcourir la documentation avant de continuer dans ce didacticiel.

Il est temps de construire

Pour que ce processus soit moins intimidant, nous le décomposerons en étapes, ce qui nous permettra de créer l'application en morceaux individuels. Voici toutes les étapes que nous allons suivre pour créer le sélecteur d'épisodes de Money Heist :

  • Échafaudez une application Create React.
  • Récupérer des épisodes.
    • Créez les types et interfaces appropriés pour nos épisodes dans interface.ts .
    • Configurez le magasin pour récupérer les épisodes dans store.tsx .
    • Créez l'action pour récupérer les épisodes dans action.ts .
    • Créez un composant EpisodeList.tsx les épisodes récupérés.
    • Importez le composant EpisodesList sur notre page d'accueil en utilisant React Lazy and Suspense .
  • Ajouter des épisodes.
    • Configurez le magasin pour ajouter des épisodes dans store.tsx .
    • Créez l'action pour ajouter des épisodes dans action.ts .
  • Supprimer des épisodes.
    • Configurez le magasin pour supprimer des épisodes dans store.tsx .
    • Créez l'action de suppression d'épisodes dans action.ts .
  • Épisode préféré.
    • Importer le composant EpisodesList dans l'épisode favori.
    • Render EpisodesList à l'intérieur de l'épisode préféré.
  • Utilisation du routeur Reach pour la navigation.

Configurer React

Le moyen le plus simple de configurer React consiste à utiliser Create React App. Create React App est un moyen officiellement pris en charge pour créer des applications React d'une seule page. Il offre une configuration de construction moderne sans configuration.

Nous l'utiliserons pour amorcer l'application que nous allons construire. Depuis votre CLI, exécutez la commande ci-dessous :

 npx create-react-app react-ts-app && cd react-ts-app

Une fois l'installation réussie, démarrez le serveur React en exécutant npm start .

Réagir à la page de démarrage ( Grand aperçu )

Comprendre les interfaces et les types dans Typescript

Les interfaces dans TypeScript sont utilisées lorsque nous devons donner des types aux propriétés des objets. Par conséquent, nous utiliserions des interfaces pour définir nos types.

 interface Employee { name: string, role: string salary: number } const bestEmployee: Employee= { name: 'John Doe', role: 'IOS Developer', salary: '$8500' //notice we are using a string }

Lors de la compilation du code ci-dessus, nous verrions cette erreur : « Les types de salary de propriété sont incompatibles. La string de type n'est pas attribuable au type number .”

De telles erreurs se produisent dans TypeScript lorsqu'une propriété ou une variable se voit attribuer un type autre que le type défini. Plus précisément, l'extrait de code ci-dessus signifie que la propriété de salary a été affectée à un type de string au lieu d'un type de number .

Créons un fichier interface.ts dans notre dossier src . Copiez et collez-y ce code :

 /** |-------------------------------------------------- | All the interfaces! |-------------------------------------------------- */ export interface IEpisode { airdate: string airstamp: string airtime: string id: number image: { medium: string; original: string } name: string number: number runtime: number season: number summary: string url: string } export interface IState { episodes: Array<IEpisode> favourites: Array<IEpisode> } export interface IAction { type: string payload: Array<IEpisode> | any } export type Dispatch = React.Dispatch<IAction> export type FavAction = ( state: IState, dispatch: Dispatch, episode: IEpisode ) => IAction export interface IEpisodeProps { episodes: Array<IEpisode> store: { state: IState; dispatch: Dispatch } toggleFavAction: FavAction favourites: Array<IEpisode> } export interface IProps { episodes: Array<IEpisode> store: { state: IState; dispatch: Dispatch } toggleFavAction: FavAction favourites: Array<IEpisode> }

C'est une bonne pratique d'ajouter un "I" au nom de l'interface. Cela rend le code lisible. Cependant, vous pouvez décider de l'exclure.

Interface d'épisode

Notre API renvoie un ensemble de propriétés telles que airdate , airstamp , airtime , id , image , name , number , runtime , season , summary et url . Par conséquent, nous avons défini une interface IEpisode et défini les types de données appropriés sur les propriétés de l'objet.

Interface IState

Notre interface IState a respectivement des propriétés d' episodes et de favorites , et une interface Array<IEpisode> .

IAction

Les propriétés de l'interface IAction sont payload et type . La propriété type a un type chaîne, tandis que la charge utile a un type Array | any Array | any .

Notez que Array | any Array | any signifie un tableau de l'interface de l'épisode ou n'importe quel type.

Le type Dispatch est défini sur React.Dispatch et une interface <IAction> . Notez que React.Dispatch est le type standard de la fonction dispatch , selon la base de code @types/react react, tandis que <IAction> est un tableau de l'action Interface.

En outre, Visual Studio Code dispose d'un vérificateur TypeScript. Ainsi, en mettant simplement en surbrillance ou en survolant le code, il est assez intelligent pour suggérer le type approprié.

En d'autres termes, pour que nous puissions utiliser notre interface dans nos applications, nous devons l'exporter. Jusqu'à présent, nous avons notre magasin et nos interfaces qui contiennent le type de notre objet. Créons maintenant notre boutique. Notez que les autres interfaces suivent les mêmes conventions que celles expliquées.

Récupérer des épisodes

Création d'un magasin

Pour récupérer nos épisodes, nous avons besoin d'un magasin qui contient l'état initial des données et qui définit notre fonction de réduction.

Nous utiliserons le crochet useReducer pour configurer cela. Créez un fichier store.tsx dans votre dossier src . Copiez et collez-y le code suivant.

 import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} } import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} } import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} } import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }

Voici les étapes que nous avons suivies pour créer le magasin :

  • Pour définir notre magasin, nous avons besoin du hook useReducer et de l'API createContext de React, c'est pourquoi nous l'avons importé.
  • Nous avons importé IState et IAction depuis ./types/interfaces .
  • Nous avons déclaré un objet initialState avec un type de IState , et les propriétés des épisodes et des favoris, qui sont tous deux définis sur un tableau vide, respectivement.
  • Ensuite, nous avons créé une variable Store qui contient la méthode createContext et qui est passée initialState .

Le type de méthode createContext est <IState | any> <IState | any> , ce qui signifie qu'il peut s'agir d'un type de <IState> ou any . Nous verrons le any type souvent utilisé dans cet article.

  • Ensuite, nous avons déclaré une fonction de reducer et passé state et l' action en tant que paramètres. La fonction reducer a une instruction switch qui vérifie la valeur de action.type . Si la valeur est FETCH_DATA , alors elle renvoie un objet qui a une copie de notre état (...state) et de l'état de l'épisode qui contient notre charge utile d'action.
  • Dans l'instruction switch, nous renvoyons un état de default .

Notez que les paramètres d' state et action dans la fonction de réduction ont respectivement les types IState et IAction . En outre, la fonction de reducer a un type de IState .

  • Enfin, nous avons déclaré une fonction StoreProvider . Cela donnera à tous les composants de notre application un accès au magasin.
  • Cette fonction prend les children comme prop, et à l'intérieur de la fonction StorePrivder , nous avons déclaré le crochet useReducer .
  • Nous avons déstructuré state et l' dispatch .
  • Afin de rendre notre magasin accessible à tous les composants, nous avons passé une valeur d'objet contenant state et dispatch .

L' state qui contient nos épisodes et l'état de nos favoris sera rendu accessible par d'autres composants, tandis que l' dispatch est une fonction qui change l'état.

  • Nous allons exporter Store et StoreProvider , afin qu'ils puissent être utilisés dans notre application.

Créer Action.ts

Nous devrons faire des requêtes à l'API pour récupérer les épisodes qui seront montrés à l'utilisateur. Cela se fera dans un fichier d'action. Créez un fichier Action.ts , puis collez le code suivant :

 import { Dispatch } from './interface/interfaces' export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON.\_embedded.episodes }) }

Tout d'abord, nous devons importer nos interfaces afin qu'elles puissent être utilisées dans ce fichier. Les étapes suivantes ont été suivies pour créer l'action :

  • La fonction fetchDataAction prend les props dispatch comme paramètre.
  • Parce que notre fonction est asynchrone, nous utiliserions async et await .
  • Nous créons une variable ( URL ) qui contient notre point de terminaison API.
  • Nous avons une autre variable nommée data qui contient la réponse de l'API.
  • Ensuite, nous stockons la réponse JSON dans dataJSON , après avoir obtenu la réponse au format JSON en appelant data.json() .
  • Enfin, nous renvoyons une fonction de répartition qui a une propriété de type et une chaîne de FETCH_DATA . Il a également un payload() . _embedded.episodes est le tableau de l'objet episodes de notre endpoint .

Notez que la fonction fetchDataAction récupère notre point de terminaison, le convertit en objets JSON et renvoie la fonction dispatch, qui met à jour l'état déclaré précédemment dans le Store.

Le type de dispatch exporté est défini sur React.Dispatch . Notez que React.Dispatch est le type standard de la fonction dispatch selon la base de code @types/react react, tandis que <IAction> est un tableau de l'action d'interface.

Composant EpisodesList

Afin de maintenir la réutilisabilité de notre application, nous conserverons tous les épisodes récupérés dans un fichier séparé, puis importerons le fichier dans notre composant homePage .

Dans le dossier des components , créez un fichier EpisodesList.tsx , puis copiez-collez-y le code suivant :

 import React from 'react' import { IEpisode, IProps } from '../types/interfaces' const EpisodesList = (props: IProps): Array<JSX.Element> => { const { episodes } = props return episodes.map((episode: IEpisode) => { return ( <section key={episode.id} className='episode-box'> <img src={!!episode.image ? episode.image.medium : ''} alt={`Money Heist ${episode.name}`} /> <div>{episode.name}</div> <section style={{ display: 'flex', justifyContent: 'space-between' }}> <div> Season: {episode.season} Number: {episode.number} </div> <button type='button' > Fav </button> </section> </section> ) }) } export default EpisodesList
  • Nous importons IEpisode et IProps depuis interfaces.tsx .
  • Ensuite, nous créons une fonction EpisodesList qui prend des accessoires. Les props auront un type de IProps , tandis que la fonction a un type de Array<JSX.Element> .

Visual Studio Code suggère que notre type de fonction soit écrit sous JSX.Element[] .

Visual Studio Code suggère un type ( Grand aperçu )

Alors que Array<JSX.Element> est égal à JSX.Element[] , Array<JSX.Element> est appelé l'identité générique. Par conséquent, le modèle générique sera souvent utilisé dans cet article.

  • À l'intérieur de la fonction, nous déstructurons les episodes de props , qui a le IEpisode comme type.

Lisez à propos de l'identité générique. Cette connaissance sera nécessaire au fur et à mesure que nous avancerons.

  • Nous avons renvoyé les accessoires des episodes et les avons cartographiés pour renvoyer quelques balises HTML.
  • La première section contient la key , qui est episode.id , et un className de episode-box , qui sera créé plus tard. Nous savons que nos épisodes ont des images ; d'où la balise d'image.
  • L'image a un opérateur ternaire qui vérifie s'il y a un episode.image ou un episode.image.medium . Sinon, nous affichons une chaîne vide si aucune image n'est trouvée. De plus, nous avons inclus l' episode.name dans une div.

Dans la section , nous montrons la saison à laquelle appartient un épisode et son numéro. Nous avons un bouton avec le texte Fav . Nous avons exporté le composant EpisodesList afin de pouvoir l'utiliser dans notre application.

Composant de la page d'accueil

Nous voulons que la page d'accueil déclenche l'appel API et affiche les épisodes à l'aide du composant EpisodesList que nous avons créé. Dans le dossier des components , créez le composant HomePage , puis copiez et collez-y le code suivant :

 import React, { useContext, useEffect, lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces' import { fetchDataAction } from '../Actions' const EpisodesList = lazy<any>(() => import('./EpisodesList')) const HomePage = (): JSX.Element => { const { state, dispatch } = useContext(Store) useEffect(() => { state.episodes.length === 0 && fetchDataAction(dispatch) }) const props: IEpisodeProps = { episodes: state.episodes, store: { state, dispatch } } return ( <App> <Suspense fallback={<div>loading...</div>}> <section className='episode-layout'> <EpisodesList {...props} /> </section> </Suspense> </App> ) } export default HomePage
  • Nous importons useContext , useEffect , lazy et Suspense de React. Le composant d'application importé est le socle sur lequel tous les autres composants doivent recevoir la valeur du magasin.
  • Nous importons également Store , IEpisodeProps et FetchDataAction à partir de leurs fichiers respectifs.
  • Nous importons le composant EpisodesList à l'aide de la fonctionnalité React.lazy disponible dans React 16.6.

Le chargement paresseux de React prend en charge la convention de fractionnement de code. Ainsi, notre composant EpisodesList est chargé dynamiquement, au lieu d'être chargé en une fois, améliorant ainsi les performances de notre application.

  • Nous déstructurons l' state et dispatch en tant qu'accessoires depuis le Store .
  • L'esperluette (&&) dans le crochet useEffect vérifie si l'état de nos épisodes est empty (ou égal à 0). Sinon, nous renvoyons la fonction fetchDataAction .
  • Enfin, nous renvoyons le composant App . À l'intérieur, nous utilisons le wrapper Suspense et définissons le fallback sur une div avec le texte de loading . Cela sera affiché à l'utilisateur pendant que nous attendons la réponse de l'API.
  • Le composant EpisodesList montera lorsque les données seront disponibles, et les données qui contiendront les episodes seront ce que nous y diffuserons.

Configurer Index.txs

Le composant Homepage doit être un enfant du StoreProvider . Nous devrons le faire dans le fichier d' index . Renommez index.js en index.tsx et collez le code suivant :

 import React from 'react' import ReactDOM from 'react-dom' import './index.css' import { StoreProvider } from './Store' import HomePage from './components/HomePage' ReactDOM.render( <StoreProvider> <HomePage /> </StoreProvider>, document.getElementById('root') )

Nous importons StoreProvider , HomePage et index.css à partir de leurs fichiers respectifs. We wrap the HomePage component in our StoreProvider . This makes it possible for the Homepage component to access the store, as we saw in the previous section.

Nous sommes venus de loin. Let's check what the app looks like, without any CSS.

App without CSS (Large preview)

Create Index.css

Delete the code in the index.css file and replace it with this:

 html { font-size: 14px; } body { margin: 0; padding: 0; font-size: 10px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .episode-layout { display: flex; flex-wrap: wrap; min-width: 100vh; } .episode-box { padding: .5rem; } .header { display: flex; justify-content: space-between; background: white; border-bottom: 1px solid black; padding: .5rem; position: sticky; top: 0; }

Our app now has a look and feel. Here's how it looks with CSS.

( Grand aperçu )

Now we see that our episodes can finally be fetched and displayed, because we've adopted TypeScript all the way. Great, isn't it?

Add Favorite Episodes Feature

Let's add functionality that adds favorite episodes and that links it to a separate page. Let's go back to our Store component and add a few lines of code:

Note that the highlighted code is newly added:

 import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext<IState | any>(initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload }
 case 'ADD_FAV': return { ...state, favourites: [...state.favourites, action.payload] }
 default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return <Store.Provider value={{ state, dispatch }}>{children}</Store.Provider> }

To implement the “Add favorite” feature to our app, the ADD_FAV case is added. It returns an object that holds a copy of our previous state, as well as an array with a copy of the favorite state , with the payload .

We need an action that will be called each time a user clicks on the FAV button. Let's add the highlighted code to index.tx :

 import { IAction, IEpisode, Dispatch } from './types/interfaces'
export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON._embedded.episodes }) }
export const toggleFavAction = (dispatch: any, episode: IEpisode | any): IAction => { let dispatchObj = { type: 'ADD_FAV', payload: episode } return dispatch(dispatchObj) }
export const toggleFavAction = (dispatch: any, episode: IEpisode | any): IAction => { let dispatchObj = { type: 'ADD_FAV', payload: episode } return dispatch(dispatchObj) }

We create a toggleFavAction function that takes dispatch and episodes as parameters, and any and IEpisode|any as their respective types, with IAction as our function type. We have an object whose type is ADD_FAV and that has episode as its payload. Lastly, we just return and dispatch the object.

Nous ajouterons quelques extraits supplémentaires à EpisodeList.tsx . Copiez et collez le code en surbrillance :

 import React from 'react' import { IEpisode, IProps } from '../types/interfaces' const EpisodesList = (props: IProps): Array<JSX.Element> => {
 const { episodes, toggleFavAction, favourites, store } = props const { state, dispatch } = store

 return episodes.map((episode: IEpisode) => { return ( <section key={episode.id} className='episode-box'> <img src={!!episode.image ? episode.image.medium : ''} alt={`Money Heist - ${episode.name}`} /> <div>{episode.name}</div> <section style={{ display: 'flex', justifyContent: 'space-between' }}> <div> Seasion: {episode.season} Number: {episode.number} </div> <button type='button'
 onClick={() => toggleFavAction(state, dispatch, episode)} > {favourites.find((fav: IEpisode) => fav.id === episode.id) ? 'Unfav' : 'Fav'}
 </button> </section> </section> ) }) } export default EpisodesList

Nous incluons togglefavaction , favorites et store comme accessoires, et nous déstructurons state , une dispatch du magasin. Afin de sélectionner notre épisode préféré, nous incluons la méthode toggleFavAction dans un événement onClick et transmettons les accessoires state , dispatch et episode comme arguments à la fonction.

Enfin, nous parcourons l'état favorite pour vérifier si fav.id (ID favori) correspond à episode.id . Si c'est le cas, nous basculons entre le texte Unfav et Fav . Cela aide l'utilisateur à savoir s'il a ajouté cet épisode à ses favoris ou non.

Nous approchons de la fin. Mais nous avons encore besoin d'une page où les épisodes favoris peuvent être liés lorsque l'utilisateur choisit parmi les épisodes sur la page d'accueil.

Si vous êtes arrivé jusqu'ici, donnez-vous une tape dans le dos.

Composant de la page de favoris

Dans le dossier des components , créez un fichier FavPage.tsx . Copiez et collez-y le code suivant :

 import React, { lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces' import { toggleFavAction } from '../Actions' const EpisodesList = lazy<any>(() => import('./EpisodesList')) export default function FavPage(): JSX.Element { const { state, dispatch } = React.useContext(Store) const props: IEpisodeProps = { episodes: state.favourites, store: { state, dispatch }, toggleFavAction, favourites: state.favourites } return ( <App> <Suspense fallback={<div>loading...</div>}> <div className='episode-layout'> <EpisodesList {...props} /> </div> </Suspense> </App> ) }

Pour créer la logique derrière le choix des épisodes préférés, nous avons écrit un petit code. Nous importons lazy et Suspense de React. Nous importons également Store , IEpisodeProps et toggleFavAction à partir de leurs fichiers respectifs.

Nous importons notre composant EpisodesList à l'aide de la fonctionnalité React.lazy . Enfin, nous renvoyons le composant App . À l'intérieur, nous utilisons le wrapper Suspense et définissons un repli sur une div avec le texte de chargement.

Cela fonctionne de la même manière que le composant de la page d' Homepage . Ce composant accédera au magasin pour obtenir les épisodes que l'utilisateur a mis en favoris. Ensuite, la liste des épisodes est transmise au composant EpisodesList .

Ajoutons quelques extraits supplémentaires au fichier HomePage.tsx .

Incluez le toggleFavAction de ../Actions . Incluez également la méthode toggleFavAction en tant qu'accessoires.

 import React, { useContext, useEffect, lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces'
import { fetchDataAction, toggleFavAction } from '../Actions'
const EpisodesList = lazy<any>(() => import('./EpisodesList')) const HomePage = (): JSX.Element => { const { state, dispatch } = useContext(Store) useEffect(() => { state.episodes.length === 0 && fetchDataAction(dispatch) }) const props: IEpisodeProps = { episodes: state.episodes, store: { state, dispatch },
 toggleFavAction, favourites: state.favourites
 } return ( <App> <Suspense fallback={<div>loading...</div>}> <section className='episode-layout'> <EpisodesList {...props} /> </section> </Suspense> </App> ) } export default HomePage

Notre FavPage doit être liée, nous avons donc besoin d'un lien dans notre en-tête dans App.tsx . Pour ce faire, nous utilisons Reach Router, une bibliothèque similaire à React Router. William Le explique les différences entre Reach Router et React Router.

Dans votre CLI, exécutez npm install @reach/router @types/reach__router . Nous installons à la fois la bibliothèque Reach Router et les types reach-router Reach.

Une fois l'installation réussie, importez Link depuis @reach/router .

 import React, { useContext, Fragment } from 'react' import { Store } from './tsx'
import { Link } from '@reach/router'
 const App = ({ children }: { children: JSX.Element }): JSX.Element => {
 const { state } = useContext(Store)
return ( <Fragment> <header className='header'> <div> <h1>Money Heist</h1> <p>Pick your favourite episode</p> </div>
 <div> <Link to='/'>Home</Link> <Link to='/faves'>Favourite(s): {state.favourites.length}</Link> </div>
 </header> {children} </Fragment> ) } export default App

Nous déstructurons le store de useContext . Enfin, notre maison aura un Link et un chemin vers / , tandis que notre favori a un chemin vers /faves .

{state.favourites.length} vérifie le nombre d'épisodes dans les états favoris et l'affiche.

Enfin, dans notre fichier index.tsx , nous importons les composants FavPage et HomePage , respectivement, et les encapsulons dans le Router .

Copiez le code en surbrillance dans le code existant :

 import React from 'react' import ReactDOM from 'react-dom' import './index.css' import { StoreProvider } from './Store'
import { Router, RouteComponentProps } from '@reach/router' import HomePage from './components/HomePage' import FavPage from './components/FavPage' const RouterPage = ( props: { pageComponent: JSX.Element } & RouteComponentProps ) => props.pageComponent
ReactDOM.render( <StoreProvider>
 <Router> <RouterPage pageComponent={<HomePage />} path='/' /> <RouterPage pageComponent={<FavPage />} path='/faves' /> </Router>
 </StoreProvider>, document.getElementById('root') )

Voyons maintenant comment fonctionne l' ADD_FAV implémenté.

Le code "Ajouter un favori" fonctionne ( Grand aperçu )

Supprimer la fonctionnalité favorite

Enfin, nous ajouterons la fonction "Supprimer l'épisode", de sorte que lorsque le bouton est cliqué, nous basculons entre l'ajout ou la suppression d'un épisode favori. Nous afficherons le nombre d'épisodes ajoutés ou supprimés dans l'en-tête.

BOUTIQUE

Pour créer la fonctionnalité "Supprimer l'épisode favori", nous ajouterons un autre boîtier dans notre boutique. Allez donc sur Store.tsx et ajoutez le code en surbrillance :

 import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext<IState | any>(initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } case 'ADD_FAV': return { ...state, favourites: [...state.favourites, action.payload] }
 case 'REMOVE_FAV': return { ...state, favourites: action.payload }
 default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }

Nous ajoutons encore un autre cas nommé REMOVE_FAV et renvoyons un objet contenant la copie de notre initialState . En outre, l'état des favorites contient la charge utile de l'action.

ACTION

Copiez le code en surbrillance suivant et collez-le dans action.ts :

 import { IAction, IEpisode, IState, Dispatch } from './types/interfaces'
export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON.\_embedded.episodes }) } //Add IState withits type
export const toggleFavAction = (state: IState, dispatch: any, episode: IEpisode | any): IAction => { const episodeInFav = state.favourites.includes(episode)
 let dispatchObj = { type: 'ADD_FAV', payload: episode }
 if (episodeInFav) { const favWithoutEpisode = state.favourites.filter( (fav: IEpisode) => fav.id !== episode.id ) dispatchObj = { type: 'REMOVE_FAV', payload: favWithoutEpisode }
 } return dispatch(dispatchObj) }

Nous importons l'interface IState à partir de ./types/interfaces , car nous devrons la transmettre comme type aux props d' state dans la fonction toggleFavAction .

Une variable episodeInFav est créée pour vérifier si un épisode existe dans l'état des favorites .

Nous filtrons à travers l'état des favoris pour vérifier si un ID de favori n'est pas égal à un ID d'épisode. Ainsi, le dispatchObj se voit réattribuer un type de REMOVE_FAV et une charge utile de favWithoutEpisode .

Prévisualisons le résultat de notre application.

Conclusion

Dans cet article, nous avons vu comment configurer TypeScript dans un projet React et comment migrer un projet de vanilla React vers TypeScript.

Nous avons également créé une application avec TypeScript et React pour voir comment TypeScript est utilisé dans les projets React. J'espère que vous avez pu apprendre certaines choses.

Veuillez partager vos commentaires et expériences avec TypeScript dans la section des commentaires ci-dessous. J'aimerais voir ce que vous proposez!

Le référentiel de prise en charge de cet article est disponible sur GitHub.

Les références

  1. "Comment migrer une application React vers TypeScript", Joe Previte
  2. "Pourquoi et comment utiliser TypeScript dans votre application React ?", Mahesh Haldar