Cos'è TypeScript e perché dovrei usarlo al posto di JavaScript?

Puoi descrivere cos'è il linguaggio TypeScript?

Cosa può fare che JavaScript o le librerie disponibili non possono fare, che mi darebbe motivo di considerarlo?

Soluzione

Ho originariamente scritto questa risposta quando Typescript era ancora ancora in fase di stampa. Cinque anni dopo, questa è una panoramica OK, ma guarda a Lodewijk'risposta sotto per una maggiore profondità

1000ft view...

[TypeScript][1] è un superset di JavaScript che fornisce principalmente tipizzazione statica opzionale, classi e interfacce. Uno dei grandi benefici è quello di permettere agli IDE di fornire un ambiente più ricco per individuare gli errori comuni *mentre si digita il codice*.

Per avere un'idea di ciò che intendo, guardate il video introduttivo di Microsoft sul linguaggio.

Per un grande progetto JavaScript, l'adozione di TypeScript potrebbe risultare in un software più robusto, pur essendo ancora distribuibile dove una normale applicazione JavaScript verrebbe eseguita.

È open source, ma si ottiene l'intelligente Intellisense mentre si digita solo se si utilizza un IDE supportato. Inizialmente, questo era solo Microsoft Visual Studio (notato anche nel post del blog di Miguel de Icaza). In questi giorni, anche altri IDE offrono il supporto a TypeScript.

Ci sono altre tecnologie simili? C'è CoffeeScript, ma quello serve davvero ad uno scopo diverso. IMHO, CoffeeScript fornisce leggibilità per gli umani, ma TypeScript fornisce anche una profonda leggibilità per gli strumenti attraverso la sua tipizzazione statica opzionale (vedi questo post recente del blog per un po' più di critica). C'è anche Dart ma questo è un sostituto completo di JavaScript (anche se può produrre codice JavaScript)

Esempio

Esempio

Come esempio, ecco un po' di TypeScript (puoi giocare con questo nel TypeScript Playground)

class Greeter {
    greeting: string;
    constructor (message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}  

Ed ecco il JavaScript che produrrebbe

var Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

Notate come TypeScript definisce il tipo delle variabili membro e dei parametri dei metodi di classe. Questo viene rimosso quando si traduce in JavaScript, ma utilizzato dall'IDE e dal compilatore per individuare gli errori, come passare un tipo numerico al costruttore.

È anche capace di dedurre tipi che non sono esplicitamente dichiarati, per esempio, determinerebbe che il metodo greet() restituisce una stringa.

Debugging di Typescript Molti browser e IDE offrono un supporto diretto al debugging attraverso le sourcemap. Vedere questa domanda di Stack Overflow per maggiori dettagli: Debug del codice TypeScript con Visual Studio

Vuoi saperne di più? Ho originariamente scritto questa risposta quando Typescript era ancora caldo di stampa. Controlla Lodewijk'risposta a questa domanda per qualche dettaglio più attuale.

Commentari (28)

TypeScript'è la relazione con JavaScript

TypeScript è un superset tipizzato di JavaScript che compila in JavaScript - typescriptlang.org. JavaScript è un linguaggio di programmazione che è sviluppato da EMCA's Technical Committee 39, che è un gruppo di persone composto da molti soggetti diversi. Il TC39 è un comitato ospitato da ECMA: un'organizzazione interna di standard. JavaScript ha molte implementazioni diverse da molti fornitori diversi (ad esempio Google, Microsoft, Oracle, ecc.). L'obiettivo di JavaScript è di essere la lingua franca del web. TypeScript è un superset del linguaggio JavaScript che ha un unico compilatore open-source ed è sviluppato principalmente da un singolo fornitore: Microsoft. L'obiettivo di TypeScript è quello di aiutare a catturare precocemente gli errori attraverso un sistema di tipi e di rendere lo sviluppo JavaScript più efficiente. Essenzialmente TypeScript raggiunge i suoi obiettivi in tre modi:

  1. Supporto per le caratteristiche moderne di JavaScript - Il linguaggio JavaScript (non il runtime) è standardizzato attraverso gli standard ECMAScript. Non tutti i browser e i runtime JavaScript supportano tutte le caratteristiche di tutti gli standard ECMAScript (vedi questa panoramica). TypeScript permette l'uso di molte delle ultime caratteristiche di ECMAScript e le traduce in vecchi target ECMAScript di tua scelta (vedi la lista dei target di compilazione sotto l'opzione compilatore --target). Questo significa che puoi tranquillamente usare le nuove caratteristiche, come i moduli, le funzioni lambda, le classi, l'operatore spread e la destrutturazione, pur rimanendo compatibile all'indietro con i vecchi browser e runtime JavaScript.
  2. Sistema di tipi avanzato - Il supporto dei tipi non fa parte dello standard ECMAScript e probabilmente non lo sarà mai a causa della natura interpretata invece che compilata di JavaScript. Il sistema di tipi di TypeScript è incredibilmente ricco e include: interfacce, enum, tipi ibridi, generici, tipi di unione/intersezione, modificatori di accesso e molto altro. Il sito ufficiale di TypeScript dà una panoramica di queste caratteristiche. Il sistema di tipi di Typescript è alla pari con la maggior parte degli altri linguaggi tipizzati e in alcuni casi probabilmente più potente.
  3. **Il compilatore di TypeScript può essere eseguito come un processo in background per supportare sia la compilazione incrementale che l'integrazione con l'IDE in modo da poter navigare più facilmente, identificare i problemi, ispezionare le possibilità e rifattorizzare il codice.

    La relazione di TypeScript con altri linguaggi di puntamento JavaScript

    TypeScript ha una filosofia unica rispetto ad altri linguaggi che compilano in JavaScript. Il codice JavaScript è codice TypeScript valido; TypeScript è un superset di JavaScript. Puoi quasi rinominare i tuoi file .js in file .ts e iniziare ad usare TypeScript (vedi "Interoperabilità JavaScript" qui sotto). I file TypeScript sono compilati in JavaScript leggibile, così che la migrazione all'indietro è possibile e comprendere il TypeScript compilato non è affatto difficile. TypeScript si basa sui successi di JavaScript mentre migliora le sue debolezze. Da un lato, avete strumenti a prova di futuro che prendono i moderni standard ECMAScript e li compilano alle vecchie versioni di JavaScript, con Babel che è il più popolare. Dall'altra parte, ci sono linguaggi che possono essere totalmente diversi da JavaScript e che mirano a JavaScript, come CoffeeScript, Clojure, Dart, Elm, Haxe, Scala.js, e tutta una serie di altri (vedi questa lista). Questi linguaggi, anche se potrebbero essere migliori di dove il futuro di JavaScript potrebbe mai portare, corrono un rischio maggiore di non trovare abbastanza adozione perché il loro futuro sia garantito. Potreste anche avere più difficoltà a trovare sviluppatori esperti per alcuni di questi linguaggi, anche se quelli che troverete possono spesso essere più entusiasti. L'interoperabilità con JavaScript può anche essere un po' più coinvolta, dal momento che sono più lontani da ciò che JavaScript è effettivamente. TypeScript si trova tra questi due estremi, bilanciando così il rischio. TypeScript non è una scelta rischiosa secondo qualsiasi standard. Ci vuole poco sforzo per abituarsi se si ha familiarità con JavaScript, poiché non è un linguaggio completamente diverso, ha un eccellente supporto per l'interoperabilità di JavaScript e ha visto un sacco di adozione di recente.

    Tipizzazione statica opzionale e inferenza dei tipi.

    JavaScript è tipizzato dinamicamente. Questo significa che JavaScript non sa che tipo è una variabile finché non viene effettivamente istanziata a run-time. Questo significa anche che potrebbe essere troppo tardi. TypeScript aggiunge il supporto ai tipi a JavaScript. I bug che sono causati da false assunzioni che una variabile sia di un certo tipo possono essere completamente sradicati se giocate bene le vostre carte (quanto rigorosamente scrivete il vostro codice o se lo scrivete affatto dipende da voi). TypeScript rende la digitazione un po' più semplice e molto meno esplicita grazie all'uso dell'inferenza dei tipi. Per esempio: var x = "hello" in TypeScript è lo stesso che var x : string = "hello". Il tipo è semplicemente dedotto dal suo uso. Anche se non digitate esplicitamente i tipi, essi sono ancora lì per salvarvi dal fare qualcosa che altrimenti risulterebbe in un errore di run-time. TypeScript è opzionalmente tipizzato per default. Per esempio function divideByTwo(x) { return x / 2 } è una funzione valida in TypeScript che può essere chiamata con qualsiasi tipo di parametro, anche se chiamarla con una stringa risulterà ovviamente in un errore runtime. Proprio come siete abituati a fare in JavaScript. Questo funziona, perché quando nessun tipo è stato assegnato esplicitamente e il tipo non può essere dedotto, come nell'esempio divideByTwo, TypeScript assegnerà implicitamente il tipo any. Questo significa che la firma del tipo della funzione divideByTwo diventa automaticamente function divideByTwo(x : any) : any. C'è un flag del compilatore per non permettere questo comportamento: --noImplicitAny. Abilitare questo flag vi dà un maggior grado di sicurezza, ma significa anche che dovrete digitare di più. I tipi hanno un costo associato ad essi. Prima di tutto, c'è una curva di apprendimento, e in secondo luogo, naturalmente, vi costerà un po' più di tempo per impostare una base di codice usando anche una corretta tipizzazione rigorosa. Nella mia esperienza, questi costi valgono totalmente su qualsiasi base di codice serio che si sta condividendo con altri. A Large Scale Study of Programming Languages and Code Quality in Github suggerisce che "i linguaggi tipizzati staticamente, in generale, sono meno inclini ai difetti rispetto ai tipi dinamici, e che la tipizzazione forte è meglio di quella debole allo stesso riguardo". È interessante notare che questo stesso documento trova che TypeScript è meno incline agli errori di JavaScript: Per quelli con coefficienti positivi possiamo aspettarci che il linguaggio sia associato, ceteris paribus, ad un maggior numero di correzioni di difetti. Questi linguaggi includono C, C++, JavaScript, Objective-C, Php, e Python. I linguaggi Clojure, Haskell, Ruby, Scala, e TypeScript, hanno tutti coefficienti negativi che implicano che questi linguaggi sono meno probabile che questi linguaggi abbiano meno probabilità della media di risultare in commit per la correzione dei difetti.

    Supporto IDE migliorato

    L'esperienza di sviluppo con TypeScript è un grande miglioramento rispetto a JavaScript. L'IDE è informato in tempo reale dal compilatore TypeScript sulle sue ricche informazioni di tipo. Questo dà un paio di grandi vantaggi. Per esempio, con TypeScript, potete tranquillamente fare refactorings come rinominare tutto il vostro codebase. Attraverso il completamento del codice, si può ottenere un aiuto in linea su qualsiasi funzione che una libreria potrebbe offrire. Non c'è più bisogno di ricordarle o di cercarle nei riferimenti online. Gli errori di compilazione sono segnalati direttamente nell'IDE con una linea rossa a ghirigori mentre si è impegnati nella codifica. Tutto sommato, questo permette un significativo guadagno di produttività rispetto al lavoro con JavaScript. Si può passare più tempo a codificare e meno tempo a fare il debug. C'è una vasta gamma di IDE che hanno un eccellente supporto per TypeScript, come Visual Studio Code, WebStorm, Atom e Sublime.

    Controlli null rigorosi

    Errori di runtime della forma cannot read property 'x' of undefined o undefined is not a function sono molto comunemente causati da bug nel codice JavaScript. TypeScript riduce già dall'inizio la probabilità che si verifichino questi tipi di errori, poiché non si può usare una variabile che non è nota al compilatore TypeScript (con l'eccezione delle proprietà delle variabili digitate "qualsiasi"). È ancora possibile però utilizzare erroneamente una variabile che è impostata su undefined. Tuttavia, con la versione 2.0 di TypeScript è possibile eliminare del tutto questo tipo di errori attraverso l'uso di tipi non annullabili. Questo funziona come segue: Con lo strict null checks abilitato (flag del compilatore --strictNullChecks) il compilatore TypeScript non permetterà che una variabile sia assegnata a undefined a meno che non si dichiari esplicitamente che è di tipo nullable. Per esempio, let x : number = undefined risulterà in un errore di compilazione. Questo si adatta perfettamente alla teoria dei tipi, poiché undefined non è un numero. Si può definire x per essere un tipo somma di number e undefined per correggere questo: let x : number | undefined = undefined. Una volta che un tipo è noto per essere nullable, cioè è di un tipo che può anche avere il valorenulloundefined, il compilatore TypeScript può determinare attraverso l'analisi del tipo basata sul flusso di controllo se il tuo codice può usare una variabile in modo sicuro o meno. In altre parole, quando controllate che una variabile siaundefinedattraverso, per esempio, un'istruzioneif`, il compilatore TypeScript dedurrà che il tipo in quel ramo del vostro codice non è più nullable e quindi può essere usato in sicurezza. Ecco un semplice esempio:

let x: number | undefined;
if (x !== undefined) x += 1; // this line will compile, because x is checked.
x += 1; // this line will fail compilation, because x might be undefined.

Durante la build, 2016 il co-progettista di TypeScript Anders Hejlsberg ha dato una spiegazione dettagliata e una dimostrazione di questa caratteristica: video (da 44:30 a 56:30).

Compilazione

Per usare TypeScript è necessario un processo di compilazione per compilare il codice JavaScript. Il processo di compilazione generalmente richiede solo un paio di secondi, a seconda ovviamente della dimensione del tuo progetto. Il compilatore TypeScript supporta la compilazione incrementale (flag --watch del compilatore) in modo che tutte le modifiche successive possano essere compilate a maggiore velocità. Il compilatore TypeScript può inlineare le informazioni sulla mappa dei sorgenti nei file .js generati o creare file .map separati. Le informazioni sulla mappa dei sorgenti possono essere usate dalle utility di debug come Chrome DevTools e altri IDE per mettere in relazione le linee nel JavaScript con quelle che le hanno generate nel TypeScript. Questo rende possibile impostare i breakpoint e ispezionare le variabili durante il runtime direttamente sul vostro codice TypeScript. Le informazioni della mappa dei sorgenti funzionano abbastanza bene, erano in circolazione molto prima di TypeScript, ma il debugging di TypeScript non è generalmente così grande come quando si usa direttamente JavaScript. Prendete la parola chiave this per esempio. A causa della semantica modificata della parola chiave this intorno alle chiusure da ES2015, this può effettivamente esistere durante il runtime come una variabile chiamata _this (vedi questa risposta). Questo può confondere durante il debug, ma generalmente non è un problema se si conosce o si ispeziona il codice JavaScript. Va notato che Babel soffre dello stesso tipo di problema. Ci sono alcuni altri trucchi che il compilatore TypeScript può fare, come generare codice di intercettazione basato su decorators, generare codice di caricamento dei moduli per diversi sistemi di moduli e analizzare JSX. Tuttavia, probabilmente avrete bisogno di uno strumento di compilazione oltre al compilatore Typescript. Per esempio, se volete comprimere il vostro codice dovrete aggiungere altri strumenti al vostro processo di compilazione per farlo. Ci sono plugin di compilazione per TypeScript disponibili per Webpack, Gulp, Grunt e praticamente qualsiasi altro strumento di compilazione JavaScript là fuori. La documentazione di TypeScript ha una sezione su integrazione con strumenti di compilazione che li copre tutti. È disponibile anche un linter nel caso in cui si desideri un controllo ancora maggiore del tempo di compilazione. Ci sono anche un gran numero di progetti seed là fuori che vi faranno iniziare con TypeScript in combinazione con un sacco di altre tecnologie come Angular 2, React, Ember, SystemJS, Webpack, Gulp, ecc.

interoperabilità di JavaScript.

Poiché TypeScript è così strettamente legato a JavaScript, ha grandi capacità di interoperabilità, ma è necessario un po' di lavoro extra per lavorare con le librerie JavaScript in TypeScript. 18definizioni di TypeScript18 sono necessarie affinché il compilatore TypeScript capisca che le chiamate a funzioni come _.groupBy o angular.copy o $.fadeOut non sono in realtà dichiarazioni illegali. Le definizioni per queste funzioni sono poste in file .d.ts. La forma più semplice che una definizione può assumere è quella di permettere ad un identificatore di essere usato in qualsiasi modo. Per esempio, quando si usa Lodash, un file di definizione a linea singola declare var _ : any vi permetterà di chiamare qualsiasi funzione vogliate su _, ma poi, naturalmente, sarete anche in grado di fare errori: _.foobar() sarebbe una chiamata legale a TypeScript, ma è, ovviamente, una chiamata illegale a run-time. Se vuoi un supporto adeguato ai tipi e il completamento del codice, il tuo file di definizione deve essere più preciso (vedi definizioni lodash per un esempio). I moduli Npm che sono preconfezionati con le proprie definizioni di tipo sono automaticamente compresi dal compilatore TypeScript (vedi documentation). Per quasi tutte le altre librerie JavaScript semi-popolari che non includono le proprie definizioni qualcuno ha già reso disponibili le definizioni dei tipi attraverso un altro modulo npm. Questi moduli hanno il prefisso "@types/" e provengono da un repository Github chiamato DefinitelyTyped. C'è un'avvertenza: le definizioni dei tipi devono corrispondere alla versione della libreria che state usando in fase di esecuzione. Se non lo fanno, TypeScript potrebbe impedirvi di chiamare una funzione o dereferenziare una variabile che esiste o permettervi di chiamare una funzione o dereferenziare una variabile che non esiste, semplicemente perché i tipi non corrispondono al run-time in fase di compilazione. Quindi assicuratevi di caricare la giusta versione delle definizioni dei tipi per la giusta versione della libreria che state usando. Ad essere onesti, c'è una leggera seccatura in questo e potrebbe essere una delle ragioni per cui non scegliete TypeScript, ma andate invece per qualcosa come Babel che non soffre affatto di dover ottenere le definizioni dei tipi. D'altra parte, se si sa cosa si sta facendo si può facilmente superare qualsiasi tipo di problema causato da file di definizione errati o mancanti.

Conversione da JavaScript a TypeScript

Qualsiasi file .js può essere rinominato in un file .ts ed eseguito attraverso il compilatore TypeScript per ottenere sintatticamente lo stesso codice JavaScript come output (se era sintatticamente corretto in primo luogo). Anche quando il compilatore TypeScript riceve errori di compilazione, produrrà comunque un file .js. Può anche accettare file .js come input con il flag --allowJs. Questo ti permette di iniziare subito con TypeScript. Sfortunatamente, è probabile che si verifichino errori di compilazione all'inizio. Bisogna ricordare che non si tratta di errori che interrompono lo spettacolo come si potrebbe essere abituati a fare con altri compilatori.
Gli errori di compilazione che si hanno all'inizio quando si converte un progetto JavaScript in un progetto TypeScript sono inevitabili per la natura di TypeScript. TypeScript controlla tutto il codice per la validità e quindi ha bisogno di conoscere tutte le funzioni e le variabili che vengono utilizzate. Quindi le definizioni dei tipi devono essere a posto per tutti loro, altrimenti gli errori di compilazione sono destinati a verificarsi. Come menzionato nel capitolo precedente, per quasi tutti i framework JavaScript ci sono file .d.ts che possono essere facilmente acquisiti con l'installazione di pacchetti DefinitelyTyped. Potrebbe, tuttavia, essere che tu abbia usato qualche oscura libreria per la quale non sono disponibili definizioni di TypeScript o che tu abbia riempito alcune primitive JavaScript. In questo caso, è necessario fornire definizioni di tipo per questi bit affinché gli errori di compilazione scompaiano. Basta creare un file .d.ts e includerlo nell'array files di tsconfig.json, in modo che sia sempre considerato dal compilatore TypeScript. In esso dichiarate quei bit che TypeScript non conosce come tipo any. Una volta che hai eliminato tutti gli errori, puoi gradualmente introdurre la tipizzazione in quelle parti secondo le tue esigenze. Un po' di lavoro sulla (ri)configurazione della pipeline di compilazione sarà anche necessario per far entrare TypeScript nella pipeline di compilazione. Come menzionato nel capitolo sulla compilazione ci sono molte buone risorse là fuori e vi incoraggio a cercare progetti seed che usino la combinazione di strumenti con cui volete lavorare. Il più grande ostacolo è la curva di apprendimento. Vi incoraggio a giocare con un piccolo progetto all'inizio. Guardate come funziona, come si costruisce, quali file usa, come è configurato, come funziona nel vostro IDE, come è strutturato, quali strumenti usa, ecc. Convertire una grande base di codice JavaScript in TypeScript è fattibile quando si sa cosa si sta facendo. Leggete questo blog per esempio su convertire 600k linee in typescript in 72 ore). Assicuratevi solo di avere una buona padronanza del linguaggio prima di fare il salto.

Adozione

TypeScript è open-source (licenza Apache 2, vedi GitHub) e sostenuto da Microsoft. Anders Hejlsberg, l'architetto principale di C# è a capo del progetto. È un progetto molto attivo; il team TypeScript ha rilasciato molte nuove funzionalità negli ultimi anni e molte altre sono ancora in programma (vedi la roadmap). Alcuni fatti sull'adozione e la popolarità:

  • Nel 2017 StackOverflow developer survey TypeScript è stato il transpiler JavaScript più popolare (9° posto assoluto) e ha vinto il terzo posto nella categoria di linguaggio di programmazione più amato.
  • Nel 2018 state of js survey TypeScript è stato dichiarato come uno dei due grandi vincitori nella categoria dei sapori JavaScript (con ES6 che è l'altro).
  • Nel 2019 StackOverlow deverloper survey TypeScript è salito al 9° posto dei linguaggi più popolari tra gli sviluppatori professionisti, superando sia C che C++. Ha di nuovo preso il terzo posto tra i linguaggi più amati.
Commentari (10)

"TypeScript Fundamentals" -- un video-corso Pluralsight di Dan Wahlin e John Papa è un ottimo, attualmente (25 marzo 2016) aggiornato per riflettere TypeScript 1.8, introduzione a Typescript.

Per me le caratteristiche veramente buone, oltre alle belle possibilità di intellisense, sono le classi, interfacce, moduli, la facilità di implementare AMD, e la possibilità di usare il debugger di Visual Studio Typescript quando invocato con IE.

Riassumendo: Se usato come previsto, Typescript può rendere la programmazione JavaScript più affidabile e più facile. Può aumentare la produttività del programmatore JavaScript in modo significativo durante l'intero SDLC.

Commentari (3)