Impostazione di TypeScript per progetti React moderni utilizzando Webpack
Pubblicato: 2022-03-10In questa era di sviluppo software, JavaScript può essere utilizzato per sviluppare quasi tutti i tipi di app. Tuttavia, il fatto che JavaScript sia digitato dinamicamente potrebbe essere un problema per la maggior parte delle grandi aziende, a causa della sua funzionalità di controllo del tipo allentata.
Fortunatamente, non dobbiamo aspettare che l'Ecma Technical Committee 39 introduca un sistema di tipi statici in JavaScript. Possiamo invece usare TypeScript.
JavaScript, essendo digitato dinamicamente, non è a conoscenza del tipo di dati di una variabile finché tale variabile non viene istanziata in fase di esecuzione. Gli sviluppatori che scrivono programmi software di grandi dimensioni potrebbero avere la tendenza a riassegnare una variabile, dichiarata in precedenza, a un valore di tipo diverso, senza alcun avviso o problema di sorta, con conseguente bug spesso trascurato.
In questo tutorial impareremo cos'è TypeScript e come lavorarci in un progetto React. Alla fine, avremo creato un progetto composto da un'app per la selezione di episodi per il programma TV Money Heist , utilizzando TypeScript e gli attuali hook simili a React ( useState
, useEffect
, useReducer
, useContext
). Con questa conoscenza, puoi continuare a sperimentare TypeScript nei tuoi progetti.
Questo articolo non è un'introduzione a TypeScript. Quindi, non esamineremo la sintassi di base di TypeScript e JavaScript. Tuttavia, non devi essere un esperto in nessuna di queste lingue per seguire, perché cercheremo di seguire il principio KISS (mantienilo semplice, stupido).
Che cos'è TypeScript?
Nel 2019, TypeScript è stata classificata come la settima lingua più utilizzata e la quinta lingua in più rapida crescita su GitHub. Ma cos'è esattamente TypeScript?
Secondo la documentazione ufficiale, TypeScript è un superset tipizzato di JavaScript che viene compilato in JavaScript semplice. È sviluppato e gestito da Microsoft e dalla comunità open source.
"Superset" in questo contesto significa che il linguaggio contiene tutte le caratteristiche e le funzionalità di JavaScript e poi alcune. TypeScript è un linguaggio di scripting tipizzato.
Offre agli sviluppatori un maggiore controllo sulla propria base di codice tramite l'annotazione del tipo, le classi e l'interfaccia, evitando agli sviluppatori di dover correggere manualmente fastidiosi bug nella console.
TypeScript non è stato creato per alterare JavaScript. Invece, espande JavaScript con nuove preziose funzionalità. Qualsiasi programma scritto in JavaScript semplice verrà eseguito anche come previsto in TypeScript, comprese le app mobili multipiattaforma e i back-end in Node.js.
Ciò significa che puoi anche scrivere app React in TypeScript, come faremo in questo tutorial.
Perché dattiloscritto?
Forse non sei convinto di abbracciare la bontà di TypeScript. Consideriamo alcuni dei suoi vantaggi.
Meno bug
Non possiamo eliminare tutti i bug nel nostro codice, ma possiamo ridurli. TypeScript controlla i tipi in fase di compilazione e genera errori se il tipo di variabile cambia.
Essere in grado di trovare questi errori evidenti ma frequenti così presto rende molto più semplice gestire il codice con i tipi.
Il refactoring è più facile
Probabilmente vuoi spesso rifattorizzare un bel po' di cose, ma poiché toccano così tanto altro codice e molti altri file, sei cauto nel modificarli.
In TypeScript, queste cose possono spesso essere rifattorizzato con un semplice clic del comando "Rinomina simbolo" nel tuo ambiente di sviluppo integrato (IDE).

In un linguaggio tipizzato dinamicamente come JavaScript, l'unico modo per refactoring di più file contemporaneamente è con la tradizionale funzione "cerca e sostituisci" utilizzando espressioni regolari (RegExp).
In un linguaggio digitato staticamente come TypeScript, "cerca e sostituisci" non è più necessario. Con i comandi IDE come "Trova tutte le occorrenze" e "Rinomina simbolo", puoi vedere tutte le occorrenze nell'app della funzione, classe o proprietà specificata di un'interfaccia oggetto.
TypeScript ti aiuterà a trovare tutte le istanze del bit rifattorizzato, rinominarlo e avvisarti con un errore di compilazione nel caso in cui il tuo codice abbia dei tipi non corrispondenti dopo il refactoring.
TypeScript ha ancora più vantaggi di quelli che abbiamo trattato qui.
Svantaggi di TypeScript
TypeScript non è sicuramente privo di svantaggi, anche date le promettenti funzionalità evidenziate sopra.
Un falso senso di sicurezza
La funzione di controllo del tipo di TypeScript crea spesso un falso senso di sicurezza tra gli sviluppatori. Il controllo del tipo ci avverte infatti quando qualcosa non va nel nostro codice. Tuttavia, i tipi statici non riducono la densità complessiva dei bug.
Pertanto, la forza del tuo programma dipenderà dal tuo utilizzo di TypeScript, perché i tipi sono scritti dallo sviluppatore e non controllati in fase di esecuzione.
Se stai cercando TypeScript per ridurre i tuoi bug, considera invece lo sviluppo basato su test.
Sistema di digitazione complicato
Il sistema di digitazione, sebbene sia un ottimo strumento sotto molti aspetti, a volte può essere un po' complicato. Questo svantaggio deriva dal fatto che è completamente interoperabile con JavaScript, il che lascia ancora più spazio alle complicazioni.
Tuttavia, TypeScript è ancora JavaScript, quindi è importante comprendere JavaScript.
Quando usare TypeScript?
Ti consiglierei di usare TypeScript nei seguenti casi:
- Se stai cercando di creare un'applicazione che verrà mantenuta per un lungo periodo , ti consiglio vivamente di iniziare con TypeScript, perché promuove l'autodocumentazione del codice, aiutando così gli altri sviluppatori a capire facilmente il tuo codice quando si uniscono alla tua base di codice .
- Se devi creare una libreria , considera di scriverla in TypeScript. Aiuterà gli editor di codice a suggerire i tipi appropriati agli sviluppatori che stanno usando la tua libreria.
Nelle ultime sezioni, abbiamo bilanciato i pro ei contro di TypeScript. Passiamo all'attività del giorno: impostare TypeScript in un moderno progetto React .
Iniziare
Esistono diversi modi per impostare TypeScript in un progetto React. In questo tutorial, ne tratteremo solo due.
Metodo 1: crea l'app React + TypeScript
Circa due anni fa, il team React ha rilasciato Create React App 2.1, con supporto TypeScript. Quindi, potresti non dover mai fare alcun lavoro pesante per inserire TypeScript nel tuo progetto.

Per avviare un nuovo progetto Create React App, puoi eseguire questo...
npx create-react-app my-app --folder-name
… o questo:
yarn create react-app my-app --folder-name
Per aggiungere TypeScript a un progetto Create React App, prima installarlo e i rispettivi @types
:
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
… o:
yarn add typescript @types/node @types/react @types/react-dom @types/jest
Quindi, rinomina i file (ad esempio, index.js
in index.tsx
) e riavvia il server di sviluppo !
È stato veloce, vero?
Metodo 2: imposta TypeScript con Webpack
Webpack è un bundler di moduli statici per applicazioni JavaScript. Prende tutto il codice dalla tua applicazione e lo rende utilizzabile in un browser web. I moduli sono blocchi di codice riutilizzabili creati da JavaScript, node_modules
, immagini e stili CSS della tua app, che sono pacchettizzati per essere facilmente utilizzati sul tuo sito web.
Crea un nuovo progetto
Iniziamo creando una nuova directory per il nostro progetto:
mkdir react-webpack cd react-webpack
Useremo npm per inizializzare il nostro progetto:
npm init -y
Il comando precedente genererà un file package.json
con alcuni valori predefiniti. Aggiungiamo anche alcune dipendenze per webpack, TypeScript e alcuni moduli specifici di React.
Installazione di pacchetti
Infine, dovremmo installare i pacchetti necessari. Apri la tua interfaccia della riga di comando (CLI) ed esegui questo:
#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
Aggiungiamo anche manualmente alcuni file e cartelle diversi nella nostra cartella react-webpack
:
- Aggiungi
webpack.config.js
per aggiungere configurazioni relative al webpack. - Aggiungi
tsconfig.json
per tutte le nostre configurazioni TypeScript. - Aggiungi una nuova directory,
src
. - Crea una nuova directory,
components
, nella cartellasrc
. - Infine, aggiungi
index.html
,App.tsx
eindex.tsx
nella cartella deicomponents
.
Struttura del progetto
Pertanto, la nostra struttura di cartelle sarà simile a questa:
├── package.json ├── package-lock.json ├── tsconfig.json ├── webpack.config.js ├── .gitignore └── src └──components ├── App.tsx ├── index.tsx ├── index.html
Inizia ad aggiungere del codice
Inizieremo con 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>
Questo creerà l'HTML, con un div
vuoto con un ID di output
.
Aggiungiamo il codice al nostro componente 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> );
Abbiamo creato un oggetto interfaccia e lo abbiamo chiamato HelloWorldProps
, con userName
e lang
aventi un tipo di string
.
Abbiamo passato gli props
di scena al nostro componente App
e l'abbiamo esportato.
Ora, aggiorniamo il codice in 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") );
Abbiamo appena importato il componente App
in index.tsx
. Quando webpack vede qualsiasi file con l'estensione .ts
o .tsx
, trasporterà quel file usando la libreria awesome-typescript-loader.
Configurazione dattiloscritta
Aggiungeremo quindi alcune configurazioni a tsconfig.json
:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "src/components/index.tsx" ] }
Diamo anche un'occhiata alle diverse opzioni che abbiamo aggiunto a tsconfig.json
:
-
compilerOptions
Rappresenta le diverse opzioni del compilatore. -
jsx:react
Aggiunge il supporto per JSX nei file.tsx
. -
lib
Aggiunge un elenco di file di libreria alla compilation (ad esempio, l'utilizzo dies2015
consente di utilizzare la sintassi ECMAScript 6). -
module
Genera il codice del modulo. -
noImplicitAny
Solleva errori per dichiarazioni con unany
tipo implicito. -
outDir
Rappresenta la directory di output. -
sourceMap
Genera un file.map
, che può essere molto utile per il debug dell'app. -
target
Rappresenta la versione ECMAScript di destinazione in cui transpilare il nostro codice (possiamo aggiungere una versione in base ai nostri requisiti specifici del browser). -
include
Utilizzato per specificare l'elenco di file da includere.
Configurazione del pacchetto web
Aggiungiamo alcune configurazioni di webpack a 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", }), ], };
Diamo un'occhiata alle diverse opzioni che abbiamo aggiunto a webpack.config.js
:
-
entry
Questo specifica il punto di ingresso per la nostra app. Potrebbe essere un singolo file o una matrice di file che vogliamo includere nella nostra build. -
output
Contiene la configurazione dell'output. L'app lo esamina quando si tenta di inviare il codice in bundle dal nostro progetto al disco. Il percorso rappresenta la directory di output in cui inviare il codice e il nome file rappresenta il nome file dello stesso. È generalmente chiamatobundle.js
. -
resolve
Webpack esamina questo attributo per decidere se raggruppare o saltare il file. Pertanto, nel nostro progetto, webpack considererà i file con le estensioni.js
,.jsx
,.json
,.ts
e.tsx
per il raggruppamento. -
module
Possiamo abilitare il webpack per caricare un file particolare quando richiesto dall'app, utilizzando i caricatori. Prende un oggetto rules che specifica che:- qualsiasi file che termina con l'estensione
.tsx
o.ts
dovrebbe utilizzareawesome-typescript-loader
di caratteri impressionante per essere caricato; - i file che terminano con l'estensione
.js
devono essere caricati consource-map-loader
; - i file che terminano con l'estensione
.css
devono essere caricati concss-loader
.
- qualsiasi file che termina con l'estensione
-
plugins
Webpack ha i suoi limiti e fornisce plugin per superarli ed estendere le sue capacità. Ad esempio,html-webpack-plugin
crea un file modello di cui viene eseguito il rendering nel browser dal fileindex.html
nella directory./src/component/index.html
.
MiniCssExtractPlugin
il rendering del file CSS
padre dell'app.
Aggiunta di script a package.json
Possiamo aggiungere diversi script per creare app React nel nostro file package.json
:
"scripts": { "start": "webpack-dev-server --open", "build": "webpack" },
Ora, esegui npm start
nella tua CLI. Se è andato tutto bene, dovresti vedere questo:

Se hai un talento per il webpack, clona il repository per questa configurazione e usalo nei tuoi progetti.
Creazione di file
Crea una cartella src
e un file index.tsx
. Questo sarà il file di base che esegue il rendering di React.
Ora, se eseguiamo npm start
, eseguirà il nostro server e aprirà una nuova scheda. L'esecuzione npm run build
creerà il webpack per la produzione e creerà una cartella di build per noi.
Abbiamo visto come configurare TypeScript da zero utilizzando l'app Create React e il metodo di configurazione del webpack.
Uno dei modi più rapidi per ottenere una conoscenza completa di TypeScript è convertire uno dei tuoi progetti vanilla React esistenti in TypeScript. Sfortunatamente, l'adozione incrementale di TypeScript in un progetto Vanilla React esistente è stressante perché comporta la necessità di espellere o rinominare tutti i file, il che comporterebbe conflitti e una richiesta pull gigante se il progetto appartenesse a un team di grandi dimensioni.
Successivamente, vedremo come migrare facilmente un progetto React in TypeScript.
Migrare un'app Create React esistente in TypeScript
Per rendere questo processo più gestibile, lo suddivideremo in passaggi, che ci consentiranno di migrare in singoli blocchi. Ecco i passaggi che adotteremo per migrare il nostro progetto:
- Aggiungi TypeScript e tipi.
- Aggiungi
tsconfig.json
. - Inizia in piccolo.
- Rinomina l'estensione dei file in
.tsx
.
1. Aggiungi TypeScript al progetto
Innanzitutto, dovremo aggiungere TypeScript al nostro progetto. Supponendo che il tuo progetto React sia stato avviato con Create React App, possiamo eseguire quanto segue:
# 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
Si noti che non abbiamo ancora cambiato nulla in TypeScript. Se eseguiamo il comando per avviare il progetto in locale ( npm start
o yarn start
), non cambia nulla. Se questo è il caso, allora fantastico! Siamo pronti per il prossimo passo.
2. Aggiungi il file tsconfig.json
Prima di sfruttare TypeScript, dobbiamo configurarlo tramite il file tsconfig.json
. Il modo più semplice per iniziare è impalcarne uno usando questo comando:
npx tsc --init
Questo ci fornisce alcune nozioni di base, con molto codice commentato. Ora, sostituisci tutto il codice in tsconfig.json
con questo:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "./src/**/**/\*" ] }
Configurazione dattiloscritta
Diamo anche un'occhiata alle diverse opzioni che abbiamo aggiunto a tsconfig.json
:
-
compilerOptions
Rappresenta le diverse opzioni del compilatore.-
target
Traduce i costrutti JavaScript più recenti in una versione precedente, come ECMAScript 5. -
lib
Aggiunge un elenco di file di libreria alla compilation (ad esempio, l'utilizzo di es2015 consente di utilizzare la sintassi ECMAScript 6). -
jsx:react
Aggiunge il supporto per JSX nei file.tsx
. -
lib
Aggiunge un elenco di file di libreria alla compilation (ad esempio, l'utilizzo di es2015 consente di utilizzare la sintassi ECMAScript 6). -
module
Genera il codice del modulo. -
noImplicitAny
Utilizzato per generare errori per dichiarazioni con un tipo implicitoany
. -
outDir
Rappresenta la directory di output. -
sourceMap
Genera un file.map
, che può essere molto utile per il debug della nostra app. -
include
Utilizzato per specificare l'elenco di file da includere.
-
Le opzioni di configurazione variano in base alla richiesta di un progetto. Potrebbe essere necessario controllare il foglio di calcolo delle opzioni di TypeScript per capire cosa si adatta al tuo progetto.
Abbiamo intrapreso solo le azioni necessarie per preparare le cose. Il nostro prossimo passo è migrare un file in TypeScript.
3. Inizia con un componente semplice
Approfitta della capacità di TypeScript di essere adottato gradualmente. Vai un file alla volta al tuo ritmo. Fai ciò che ha senso per te e il tuo team. Non cercare di affrontarlo tutto in una volta.
Per convertirlo correttamente, dobbiamo fare due cose:
- Cambia l'estensione del file in
.tsx
. - Aggiungi l'annotazione del tipo (che richiederebbe una certa conoscenza di TypeScript).
4. Rinominare le estensioni dei file in .tsx
In una grande base di codice, potrebbe sembrare faticoso rinominare i file singolarmente.
Rinomina più file su macOS
Rinominare più file può essere una perdita di tempo. Ecco come puoi farlo su un Mac. Fai clic con il pulsante destro del mouse (o Ctrl
+ clic, oppure fai clic con due dita contemporaneamente sul trackpad se stai utilizzando un MacBook) sulla cartella che contiene i file che desideri rinominare. Quindi, fai clic su "Rivela nel Finder". Nel Finder, seleziona tutti i file che desideri rinominare. Fai clic con il pulsante destro del mouse sui file selezionati e scegli "Rinomina X elementi..." Quindi vedrai qualcosa del genere:

Inserisci la stringa che vuoi trovare e la stringa con cui vuoi sostituire quella stringa trovata e premi "Rinomina". Fatto.
Rinomina più file su Windows
La ridenominazione di più file su Windows va oltre lo scopo di questo tutorial, ma è disponibile una guida completa. Di solito si ottengono errori dopo aver rinominato i file; devi solo aggiungere le annotazioni del tipo. Puoi rispolverare questo nella documentazione.
Abbiamo spiegato come configurare TypeScript in un'app React. Ora creiamo un'app per la selezione di episodi per Money Heist usando TypeScript.
Non tratteremo i tipi di base di TypeScript. È necessario esaminare la documentazione prima di continuare in questo tutorial.
Tempo per costruire
Per rendere questo processo meno scoraggiante, lo suddivideremo in passaggi, che ci consentiranno di creare l'app in singoli blocchi. Ecco tutti i passaggi che adotteremo per creare il selettore di episodi di Money Heist :
- Impalcatura di un'app Create React.
- Recupera episodi.
- Crea i tipi e le interfacce appropriati per i nostri episodi in
interface.ts
. - Configura il negozio per il recupero degli episodi in
store.tsx
. - Crea l'azione per il recupero degli episodi in
action.ts
. - Crea un componente
EpisodeList.tsx
che contenga gli episodi recuperati. - Importa il componente
EpisodesList
nella nostra home page usandoReact Lazy and Suspense
.
- Crea i tipi e le interfacce appropriati per i nostri episodi in
- Aggiungi episodi.
- Configura store per aggiungere episodi in
store.tsx
. - Crea l'azione per aggiungere episodi in
action.ts
.
- Configura store per aggiungere episodi in
- Rimuovi episodi.
- Configura lo store per eliminare gli episodi in
store.tsx
. - Crea l'azione per eliminare gli episodi in
action.ts
.
- Configura lo store per eliminare gli episodi in
- Episodio preferito.
- Importa il componente
EpisodesList
nell'episodio preferito. - Render
EpisodesList
all'interno dell'episodio preferito.
- Importa il componente
- Utilizzo di Reach Router per la navigazione.
Imposta Reagire
Il modo più semplice per configurare React è utilizzare l'app Crea React. Create React App è un modo ufficialmente supportato per creare applicazioni React a pagina singola. Offre una configurazione di build moderna senza configurazione.
Ne faremo uso per avviare l'applicazione che andremo a costruire. Dalla tua CLI, esegui il comando seguente:
npx create-react-app react-ts-app && cd react-ts-app
Una volta completata l'installazione, avviare il server React eseguendo npm start
.

Comprensione di interfacce e tipi in dattiloscritto
Le interfacce in TypeScript vengono utilizzate quando è necessario assegnare tipi alle proprietà degli oggetti. Quindi, useremmo le interfacce per definire i nostri tipi.
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 }
Durante la compilazione del codice sopra, vedremmo questo errore: “I tipi di salary
di proprietà sono incompatibili. La string
di tipo non è assegnabile al number
di tipo."
Tali errori si verificano in TypeScript quando a una proprietà oa una variabile viene assegnato un tipo diverso dal tipo definito. In particolare, lo snippet sopra indica che alla proprietà salary
è stato assegnato un tipo string
anziché un tipo number
.
Creiamo un file interface.ts
nella nostra cartella src
. Copia e incolla questo codice al suo interno:
/** |-------------------------------------------------- | 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> }
È buona norma aggiungere una "I" al nome dell'interfaccia. Rende il codice leggibile. Tuttavia, potresti decidere di escluderlo.
Interfaccia IEpisode
La nostra API restituisce un insieme di proprietà come airdate
, airstamp
, airtime
, id
, image
, name
, number
, runtime
, season
, summary
e url
. Quindi, abbiamo definito un'interfaccia IEpisode
e impostato i tipi di dati appropriati sulle proprietà dell'oggetto.
Interfaccia IState
La nostra interfaccia IState
ha rispettivamente le proprietà degli episodes
e favorites
e un'interfaccia Array<IEpisode>
.
Iazione
Le proprietà dell'interfaccia IAction
sono payload
e type
. La proprietà type
ha un tipo stringa, mentre il payload ha un tipo Array | any
Array | any
.
Si noti che Array | any
Array | any
significa un array dell'interfaccia dell'episodio o qualsiasi tipo.
Il tipo di Dispatch
è impostato su React.Dispatch
e un'interfaccia <IAction>
. Si noti che React.Dispatch
è il tipo standard per la funzione di dispatch
, in base alla base di codice @types/react
, mentre <IAction>
è un array dell'azione Interface.
Inoltre, Visual Studio Code ha un correttore TypeScript. Quindi, semplicemente evidenziando o passando sopra il codice, è abbastanza intelligente suggerire il tipo appropriato.
In altre parole, per poter utilizzare la nostra interfaccia nelle nostre app, dobbiamo esportarla. Finora, abbiamo il nostro negozio e le nostre interfacce che contengono il tipo del nostro oggetto. Creiamo ora il nostro negozio. Si noti che le altre interfacce seguono le stesse convenzioni di quelle spiegate.

Recupera episodi
Creazione di un negozio
Per recuperare i nostri episodi, abbiamo bisogno di un archivio che contenga lo stato iniziale dei dati e che definisca la nostra funzione di riduzione.
Useremo useReducer
hook per configurarlo. Crea un file store.tsx
nella tua cartella src
. Copia e incolla il codice seguente al suo interno.
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} }
Di seguito sono riportati i passaggi che abbiamo adottato per creare il negozio:
- Per definire il nostro negozio, abbiamo bisogno
useReducer
e dell'APIcreateContext
di React, motivo per cui l'abbiamo importato. - Abbiamo importato
IState
eIAction
da./types/interfaces
. - Abbiamo dichiarato un oggetto
initialState
con un tipoIState
e le proprietà degli episodi e dei preferiti, che sono entrambi impostati rispettivamente su un array vuoto. - Successivamente, abbiamo creato una variabile
Store
che contiene il metodocreateContext
e a cui viene passatoinitialState
.
Il tipo di metodo createContext
è <IState | any>
<IState | any>
, il che significa che potrebbe essere un tipo di <IState>
o any
. Vedremo any
tipo usato spesso in questo articolo.
- Successivamente, abbiamo dichiarato una funzione
reducer
e passatostate
eaction
come parametri. La funzionereducer
ha un'istruzione switch che controlla il valore diaction.type
. Se il valore èFETCH_DATA
, restituisce un oggetto che ha una copia del nostro stato(...state)
e dello stato dell'episodio che contiene il nostro payload dell'azione. - Nell'istruzione switch, restituiamo uno stato di
default
.
Si noti che i parametri di state
e action
nella funzione riduttore hanno rispettivamente i tipi IState
e IAction
. Inoltre, la funzione reducer
ha un tipo di IState
.
- Infine, abbiamo dichiarato una funzione
StoreProvider
. Ciò consentirà a tutti i componenti della nostra app di accedere allo store. - Questa funzione prende
children
come supporto e all'interno della funzioneStorePrivder
, abbiamo dichiarato l'hookuseReducer
. - Abbiamo destrutturato lo
state
e ladispatch
. - Per rendere il nostro negozio accessibile a tutti i componenti, abbiamo passato un valore oggetto contenente
state
edispatch
.
Lo state
che contiene i nostri episodi e lo stato dei preferiti sarà reso accessibile da altri componenti, mentre l' dispatch
è una funzione che cambia lo stato.
- Esporteremo
Store
eStoreProvider
, in modo che possa essere utilizzato nella nostra applicazione.
Crea Action.ts
Dovremo fare richieste all'API per recuperare gli episodi che verranno mostrati all'utente. Questo verrà fatto in un file di azione. Crea un file Action.ts
, quindi incolla il codice seguente:
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 }) }
Innanzitutto, dobbiamo importare le nostre interfacce in modo che possano essere utilizzate in questo file. Per creare l'azione sono stati eseguiti i seguenti passaggi:
- La funzione
fetchDataAction
accetta i prop didispatch
come parametro. - Poiché la nostra funzione è asincrona, utilizzeremo
async
eawait
. - Creiamo una variabile(
URL
) che contiene il nostro endpoint API. - Abbiamo un'altra variabile denominata
data
che contiene la risposta dall'API. - Quindi, memorizziamo la risposta JSON in
dataJSON
, dopo aver ottenuto la risposta in formato JSON chiamandodata.json()
. - Infine, restituiamo una funzione di invio che ha una proprietà di
type
e una stringa diFETCH_DATA
. Ha anche unpayload()
._embedded.episodes
è l'array dell'oggetto episodi dal nostroendpoint
.
Si noti che la funzione fetchDataAction
recupera il nostro endpoint, lo converte in oggetti JSON
e restituisce la funzione di invio, che aggiorna lo stato dichiarato in precedenza nello Store.
Il tipo di spedizione esportato è impostato su React.Dispatch
. Si noti che React.Dispatch
è il tipo standard per la funzione di invio in base alla base di codice @types/react
, mentre <IAction>
è un array dell'azione dell'interfaccia.
Componente elenco episodi
Per mantenere la riutilizzabilità della nostra app, manterremo tutti gli episodi recuperati in un file separato, quindi importeremo il file nel nostro componente homePage
.
Nella cartella dei components
, crea un file EpisodesList.tsx
e copia e incolla il codice seguente:
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
- Importiamo
IEpisode
eIProps
dainterfaces.tsx
. - Successivamente, creiamo una funzione
EpisodesList
che accetta oggetti di scena. Gli oggetti di scena avranno un tipo diIProps
, mentre la funzione ha un tipo diArray<JSX.Element>
.
Visual Studio Code suggerisce che il nostro tipo di funzione sia scritto come JSX.Element[]
.

Mentre Array<JSX.Element>
è uguale a JSX.Element[]
, Array<JSX.Element>
è chiamato identità generica. Pertanto, il modello generico verrà utilizzato spesso in questo articolo.
- All'interno della funzione destrutturiamo gli
episodes
daprops
, che ha come tipoIEpisode
.
Leggi l'identità generica, questa conoscenza sarà necessaria mentre procediamo.
- Abbiamo restituito gli oggetti di scena degli
episodes
e li abbiamo mappati per restituire alcuni tag HTML. - La prima sezione contiene la
key
, che èepisode.id
, e unclassName
di Episodeepisode-box
, che verrà creato in seguito. Sappiamo che i nostri episodi hanno immagini; quindi, il tag immagine. - L'immagine ha un operatore ternario che controlla se è presente un
episode.image
o unepisode.image.medium
. Altrimenti, visualizziamo una stringa vuota se non viene trovata alcuna immagine. Inoltre, abbiamo incluso l'episode.name
in un div.
Nella section
, mostriamo la stagione a cui appartiene un episodio e il suo numero. Abbiamo un pulsante con la scritta Fav
. Abbiamo esportato il componente EpisodesList
in modo da poterlo utilizzare nella nostra app.
Componente della pagina iniziale
Vogliamo che la home page attivi la chiamata API e visualizzi gli episodi utilizzando il componente EpisodesList
che abbiamo creato. All'interno della cartella dei components
, crea il componente HomePage
e copia e incolla il codice seguente su di esso:
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
- Importiamo
useContext
,useEffect
,lazy
eSuspense
da React. Il componente dell'app importato è la base su cui tutti gli altri componenti devono ricevere il valore del negozio. - Importiamo anche
Store
,IEpisodeProps
eFetchDataAction
dai rispettivi file. - Importiamo il componente
EpisodesList
utilizzando la funzioneReact.lazy
disponibile in React 16.6.
React lazy loading supporta la convenzione di suddivisione del codice. Pertanto, il nostro componente EpisodesList
viene caricato dinamicamente, invece di essere caricato in una volta, migliorando così le prestazioni della nostra app.
- Destrutturiamo lo
state
edispatch
come oggetti di scena dalStore
. - La e commerciale (&&)
useEffect
controlla se lo stato degli episodi èempty
(o uguale a 0). Altrimenti, restituiamo la funzionefetchDataAction
. - Infine, restituiamo il componente
App
. Al suo interno, utilizziamo il wrapperSuspense
e impostiamo ilfallback
su un div con il testo diloading
. Questo verrà mostrato all'utente mentre attendiamo la risposta dall'API. - Il componente
EpisodesList
si attiverà quando i dati saranno disponibili e i dati che conterranno gliepisodes
sono ciò che ci diffondiamo.
Imposta Index.txs
Il componente Homepage
deve essere figlio di StoreProvider
. Dovremo farlo nel file di index
. Rinomina index.js
in index.tsx
e incolla il codice seguente:
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') )
Importiamo StoreProvider
, HomePage
e index.css
dai rispettivi file. 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.
Abbiamo fatto molta strada. Let's check what the app looks like, without any CSS.

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.

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.
Aggiungeremo altri frammenti a EpisodeList.tsx
. Copia e incolla il codice evidenziato:
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
togglefavaction
, favorites
e store
come oggetti di scena e destrutturiamo state
, una dispatch
dal negozio. Per selezionare il nostro episodio preferito, includiamo il metodo toggleFavAction
in un evento onClick
e passiamo lo state
, l' dispatch
e gli oggetti di scena episode
come argomenti alla funzione.
Infine, esaminiamo lo stato favorite
per verificare se fav.id
(ID preferito) corrisponde a episode.id
. In tal caso, alterniamo tra il testo Unfav
e Fav
. Questo aiuta l'utente a sapere se ha preferito quell'episodio o meno.
Ci stiamo avvicinando alla fine. Ma abbiamo ancora bisogno di una pagina a cui collegare gli episodi preferiti quando l'utente sceglie tra gli episodi in home page.
Se sei arrivato fin qui, datti una pacca sulla spalla.
Componente Favpage
Nella cartella dei components
, crea un file FavPage.tsx
. Copia e incolla il codice seguente:
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> ) }
Per creare la logica alla base della scelta degli episodi preferiti, abbiamo scritto un piccolo codice. Importiamo lazy
e Suspense
da React. Importiamo anche Store
, IEpisodeProps
e toggleFavAction
dai rispettivi file.
Importiamo il nostro componente EpisodesList
utilizzando la funzione React.lazy
. Infine, restituiamo il componente App
. Al suo interno, utilizziamo il wrapper Suspense
e impostiamo un fallback su un div con il testo di caricamento.
Funziona in modo simile al componente Homepage
. Questo componente accederà allo store per ottenere gli episodi che l'utente ha preferito. Quindi, l'elenco degli episodi viene passato al componente EpisodesList
.
Aggiungiamo altri frammenti al file HomePage.tsx
.
Includi toggleFavAction
da ../Actions
. Includere anche il metodo toggleFavAction
come oggetti di scena.
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
La nostra FavPage
deve essere collegata, quindi abbiamo bisogno di un collegamento nella nostra intestazione in App.tsx
. Per raggiungere questo obiettivo, utilizziamo Reach Router, una libreria simile a React Router. William Le spiega le differenze tra Reach Router e React Router.
Nella tua CLI, esegui npm install @reach/router @types/reach__router
. Stiamo installando sia la libreria Reach Router che i tipi reach-router
Reach.
Al termine dell'installazione, importa Link
da @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
Destrutturiamo il negozio da useContext
. Infine, la nostra casa avrà un Link
e un percorso verso /
, mentre la nostra preferita avrà un percorso verso /faves
.
{state.favourites.length}
controlla il numero di episodi negli stati preferiti e lo visualizza.
Infine, nel nostro file index.tsx
, importiamo rispettivamente i componenti FavPage
e HomePage
e li avvolgiamo nel Router
.
Copia il codice evidenziato nel codice esistente:
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') )
Ora, vediamo come funziona ADD_FAV
implementato.

Rimuovi la funzionalità preferita
Infine, aggiungeremo la "funzione Rimuovi episodio", in modo che quando si fa clic sul pulsante, si alterna tra l'aggiunta o la rimozione di un episodio preferito. Visualizzeremo il numero di episodi aggiunti o rimossi nell'intestazione.
NEGOZIO
Per creare la funzionalità "Rimuovi episodio preferito", aggiungeremo un altro caso nel nostro negozio. Quindi, vai su Store.tsx
e aggiungi il codice evidenziato:
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} }
Aggiungiamo ancora un altro case chiamato REMOVE_FAV
e restituiamo un oggetto contenente la copia del nostro initialState
. Inoltre, lo stato dei favorites
contiene il carico utile dell'azione.
AZIONE
Copia il seguente codice evidenziato e incollalo in 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) }
Importiamo l'interfaccia IState
da ./types/interfaces
, perché dovremo passarla come tipo agli oggetti di state
nella funzione toggleFavAction
.
Viene creata una variabile episodeInFav
per verificare se esiste un episodio nello stato dei favorites
.
Filtramo lo stato dei preferiti per verificare se un ID preferito non è uguale a un ID episodio. Pertanto, a dispatchObj
viene riassegnato un tipo di REMOVE_FAV
e un payload di favWithoutEpisode
.
Vediamo in anteprima il risultato della nostra app.
Conclusione
In questo articolo, abbiamo visto come impostare TypeScript in un progetto React e come migrare un progetto da vanilla React a TypeScript.
Abbiamo anche creato un'app con TypeScript e React per vedere come viene utilizzato TypeScript nei progetti React. Confido che tu sia stato in grado di imparare alcune cose.
Per favore condividi il tuo feedback e le tue esperienze con TypeScript nella sezione commenti qui sotto. Mi piacerebbe vedere cosa ti viene in mente!
Il repository di supporto per questo articolo è disponibile su GitHub.
Riferimenti
- "Come migrare un'app React in TypeScript", Joe Previte
- "Perché e come utilizzare TypeScript nella tua app React?", Mahesh Haldar