back to top

Introduzione a TypeScript

In questa guida illustreremo brevemente i concetti basilari per iniziare a usare TypeScript. Faremo riferimento alla versione v2.7.1 che è l’ultima versione disponibile al momento della stesura di questa guida.

guida introduttiva a typescript

Cos’è TypeScript

TypeScript è un liguaggio di programmazione open-source sviluppato da Microsoft che estende il linguaggio Javascript aggiungendo alcuni costrutti sintattici e mettendo a disposizione delle funzionalità che non sono ancora supportate dalla versione corrente di Javascript.

TypeScript estende il linguaggio Javascript

È opportuno sottolineare che il codice scritto in TypeScript deve essere convertito in linguaggio Javascript prima di poter essere eseguito. Per far ciò viene usato un transpiler, ovvero un tool grazie al quale è possibile convertire il codice sorgente da un certo linguaggio a un altro. Visto che alla fine è comunque il motore Javascript ad eseguire il codice delle applicazioni scritte originariamente in TypeScript, i file Javascript possono essere usati senza problemi all’interno di un’applicazione TypeScript.

Come vedremo, i file TypeScript hanno solitamente estensione .ts (.tsx nel caso si voglia usare JSX nel file). Se all’interno di uno di questi file inseriamo del semplice codice Javascript, il compilatore TypeScript non segnalerà nessun errore in quanto il codice Javascript è codice TypeScript.

schema di funzionamento del compilatore TypeScript

TypeScript può essere usato per sviluppare delle applicazioni al posto di JavaScript ed è quindi possibile impiegarlo sia lato client che server, per sviluppare applicazioni Desktop con Electron o applicazioni mobili con NativeScript o React Native. TypeScript è il linguaggio consigliato per lo sviluppo di applicazioni Angular, ma è anche supportato da Vue.js e React. (Nel caso di React e React Native può essere utile valutare l’impiego di Flow che fornisce delle funzionalità simili a TypeScript)

Perché usare TypeScript

Javascript è un linguaggio a tipizzazione dinamica debole, ovvero un linguaggio in cui il controllo del tipo di una variabile viene effettuato a runtime invece che in fase di compilazione. Il tipo di ciascuna variabile può anche cambiare dinamicamente durante l’esecuzione di un programma. Questa caratteristica rende Javascript un linguaggio estremamente flessibile, ma, nello stesso tempo, il codice può risultare ambiguo e può causare degli errori di cui ci si accorge solamente in fase di esecuzione.

TypeScript è stato creato con l’obiettivo di risolvere anche i problemi appena esposti eseguendo il controllo dei tipi in fase di compilazione. TypeScript mette a disposizione il sistema opzionale delle annotazioni dei tipi che consente di specificare in maniera esplicita il tipo di una variabile, rendendo così il codice più comprensibile e leggibile. Tutto ciò comporta notevoli vantaggi soprattutto nella realizzazione di applicazioni complesse.

Per illustrare meglio quanto esposto finora, creiamo un semplice file app.js come riportato sotto. Useremo Node.js per eseguire il frammento di codice in esso presente.

// app.js
let argomenti;

function somma(addendo1 = 0, addendo2 = 0) {
  return addendo1 + addendo2;
}

if (process.argv.length > 2) {
  argomenti = process.argv.slice(2);
  // il risultato non è quello atteso
  console.log('Il risultato della somma è: ' + somma(...argomenti));
}

Abbiamo creato una semplice funzione somma() che accetta come argomenti due addendi e restituisce la loro somma. Proviamo quindi a invocare tale funzione usando come argomenti i valori passati tramite linea di comando.

$ node app.js 1 2
Il risultato della somma è: 12

Il risultato non è quello sperato e il motivo è che l’array argomenti ([‘1’, ‘2’]) contiene al suo interno due stringhe rappresentanti i caratteri ‘1’ e ‘2’. Infatti, gli argomenti passati tramite linea di comando, e contenuti all’interno dell’array process.argv, sono delle stringhe.

[ '/Users/claudio/.nvm/versions/node/v8.9.4/bin/node',
'/Users/claudio/guida_typescript/app.js',
'1',
'2' ]

Sebbene il codice scritto sia concettualmente corretto, avremmo dovuto controllare il tipo degli argomenti ricevuti prima di completare l’esecuzione della funzione somma().

Nel caso di TypeScript, ci viene segnalato se il tipo dei dati passati alla funzione somma() è corretto o meno.

// app.ts - VERSIONE ERRATA
let argomenti: number[];

function somma(addendo1 = 0, addendo2 = 0): number {
  return addendo1 + addendo2;
}

if (process.argv.length > 2) {
  // qui ci viene segnalato un errore come mostrato nell'immagine in basso
  argomenti = process.argv.slice(2);  
  console.log(somma(...argomenti));
}

All’interno del file app.ts abbiamo specificato che la variabile argomenti è un array di tipo number. Provando quindi ad assegnare a quest’ultima l’array restituito dalla funzione process.argv.slice(2), ci viene segnalato un errore. (La funzione Array.prototype.slice([inizio[, fine]]) restituisce una copia dell’array originale contenente, in questo caso, gli ultimi due elementi dell’array originale)

messaggio errore tipo compilatore typescript

Prendendo nuovamente in considerazione la funzione somma(), abbiamo indicato che quest’ultima deve restituire un valore numerico. A tal proposito abbiamo inserito il carattere ‘: ‘ immediatamente dopo la parentesi tonda, seguito dal tipo number che deve essere restituito dalla funzione. (somma(addendo1 = 0, addendo2 = 0): number) La funzione somma() riceve quindi in ingresso due numeri e restituisce un valore numerico.

Abbiamo già detto che le annotazioni sono opzionali. Facendo sempre riferimento alla funzione somma(), dal momento che entrambi gli addendi hanno zero come valore di default, TypeScript è in grado di dedurre che i due argomenti da passare alla funzione devono essere di tipo number.

inferenza di tipo in typescript

Correggiamo quindi il file app.ts in modo che venga assegnato alla variabile argomenti un array i cui elementi siano di tipo number.

// app.ts
let argomenti: number[];

function somma(addendo1 = 0, addendo2 = 0): number {
  return addendo1 + addendo2;
}

if (process.argv.length > 2) {
  argomenti = process.argv
    .slice(2)
    .map(value => parseInt(value, 10));
  console.log(`Il risultato della somma è: ${somma(...argomenti)}`);
}

Dopo aver generato il file app.js a partire dal file app.ts (vedremo a breve come fare), possiamo verificare che tutto funzioni correttamente attraverso il seguente comando.

$ node app.js 1 2
Il risultato della somma è: 3

È quindi possibile sfruttare il compilatore TypeScript per individuare eventuali errori (magari anche semplici errori di battitura) già in fase di compilazione. Bisogna comunque evidenziare che TypeScript genererà i file Javascript anche in caso siano presenti degli errori all’interno del file originario con estensione .ts.

TypeScript permette anche di utilizzare all’interno delle applicazioni delle funzionalità che non sono ancora disponibili nella versione corrente di Javascript e che quindi non sarebbero interpretate dai motori disponibili attualmente.

All’interno di un progetto in cui si usa TypeScript è comunque possibile integrare delle librerie esterne scritte in Javascript. TypeScript consente di creare dei file di definizione per una libreria Javascript che permettono al compilatore di conoscere la segnatura delle varie funzioni della libreria o i tipi delle variabili usate. Si tratta di file grazie ai quali il compilatore è in grado di determinare la segnatura delle funzioni o la struttura degli oggetti della libreria. In questo modo potremo avere, anche nel caso di una libreria Javascript, tutti i vantaggi del linguaggio TypeScript come il controllo statico dei tipi o funzionalità come l’autocompletamento del codice.

Infatti, è bene sottolineare che nell’esempio appena visto abbiamo usato alcune variabili globali di Node.js come l’oggetto process. Normalmente TypeScript mostrerebbe un messaggio di errore come quello riportato sotto perché non riconosce la variabile process.

errore variabile globale node js non riconosciuta da TypeScript

È possibile risolvere il problema aggiungendo al progetto il file di dichiarazione di Node.js. In TypeScript 2+ il modo più semplice è usare il comando NPM. È stata messa a disposizione una vasta collezione di file di dichiarazione delle librerie e tool Javascript più popolari che è possibile visualizzare sul sito npmjs.com. È stata anche creata una pagina apposita in cui cercare i file di dichiarazione. Nel nostro caso, dopo aver inizializzato il progetto col comando npm init -y, possiamo installare il file di dichiarazione di Node.js col seguente comando:

$ npm install @types/node --save-dev

Dopo questa operazione TypeScript non mostrerà più un messaggio di errore come quello visto sopra.

file app ts dopo installazione file definizione node js

Il file di configurazione tsconfig.json e il comando tsc

Nell’esempio illustrato in precedenza abbiamo creato il file app.ts contenente il codice TypeScript che dobbiamo compilare in un nuovo file app.js in cui è presente il codice Javascript che verrà effettivamente eseguito. Per far ciò possiamo installare il transpiler attraverso NPM. Dopo aver installato Node.js sul nostro computer, possiamo lanciare il seguente comando:

$ npm install -g typescript

Abbiamo installato TypeScript globalmente (-g) in modo da poter lanciare il comando tsc nella shell. Se l’installazione viene completata correttamente, possiamo verificare la versione corrente del transpiler attraverso il comando riportato sotto.

$ tsc --version
Version 2.7.1

È possibile compilare il codice scritto in un file .ts e generare il corrispettivo file contenente il codice Javascript con estensione .js. (Per progetti in cui si usa Node.js può risultare conveniente usare ts-node)

# genera il file app.js all'interno della stessa cartella del file app.ts
$ tsc app.ts

Se sono presenti più file .ts, è possibile compilarli con il seguente comando:

$ tsc file1.ts file2.ts

Verranno generati altrettanti file con estensione .js. In alternativa è comunque possibile creare un solo file a partire da più file .ts.

$ tsc file1.ts file2.ts --outFile app.js

Il comando tsc accetta un gran numero di opzioni che possiamo visualizzare con il comando tsc –help. Se però non si vogliono specificare tali opzioni ogni volta che si lancia il comando, possiamo creare un file di configurazione tsconfig.json. Sebbene sia possibile crearlo manualmente, è conveniente usare il comando tsc –init che genera un nuovo file all’interno del quale è già presente una configurazione base e sono documentate le altre opzioni disponibili attraverso dei commenti.

/* Esempio file tsconfig.json */
{
  "compilerOptions": {
    "target": "es5",        /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",   /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "watch": true,
    "outDir": "js"
  }
}

Con il file tsconfig.json riportato sopra, il transpiler osserva eventuali cambiamenti dei file .ts e genera i rispettivi file .js nella cartella js. I nuovi file .js creati conterranno del codice compatibile con lo standard ES5. Abbiamo inoltre specificato che useremo il sistema dei moduli commonjs tipico di Node.js.

Terminiamo questa lezione dicendo che un file tsconfig.json può ereditare delle configurazioni da un altro file attraverso la proprietà extends.

// tsconfig.base.json
{
  "compilerOptions": {
    "target": "es5",        /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",   /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
  }
}
// tsconfig.json
{
  "extends": "../configs/tsconfig.base",
  "compilerOptions": {
    "watch": true,
    "outDir": "js"
  },
  files: [
    "app.ts",
    "lib/file1.ts"
  ]
}

Conclusioni

In questa prima lezione abbiamo visto cos’è TypeScript e quali sono i vantaggi nell’usare un tale linguaggio. Abbiamo inoltre iniziato a vedere come usare TypeScript e come configurare il transpiler attraverso il file tsconfig.json. Nella prossima lezione illustreremo alcune delle funzionalità più interessanti di TypeScript.

Pubblicitร