TypeScript TS2304 compile error in Visual Studio: come risolvere

Fixing TypeScript "Compile on Save" feature in Visual Studio 2015 ASP.NET 5 RC1

Durante un lavoro di revisione del codice sorgente di un libro di programmazione, ho recentemente avuto alcune difficoltà nel compilare la parte TypeScript di una applicazione basata su ASP.NET CoreAngular2: il problema era dovuto al fatto che il compilatore TypeScript integrato in Visual Studio 2015 non voleva assolutamente saperne di compilare il codice client, lamentando la mancanza di una serie di classi ECMAScript6 nonostante la presenza di una libreria shim apposita (l'ormai irrinunciabile core-js). Nello specifico, gli errori riscontrati erano i seguenti:

La cosa mi ha colto di sorpresa perché è cominciata subito dopo l'aggiornamento dei sorgenti Angular2 da beta-17 a RC1. Ci ho messo un bel pò a capire a cosa fosse dovuto il problema, anche per via della mancanza di documentazione a riguardo. Per questo motivo, nella speranza di essere d'aiuto a quanti come me si trovano di fronte a questa problematica, ho deciso di scrivere questo articolo.

Il Problema

Per farla breve, il problema è legato all'utilizzo di librerie TypeScript che utilizzano funzionalitàECMAScript6 (ES6) senza la presenza dei type definition file adeguati che rendano il compilatore TypeScript in grado di gestirle. E' proprio il caso di Angular2 RC1, ma anche di molte altre librerie recenti.

A questo punto è legittimo chiedersi: "come possiamo fare per rendere il compilatore TypeScript in grado di gestire le funzionalità ES6?" Ebbene, ci sono due importanti passaggi che possiamo (anzi dobbiamo) svolgere:

  1. Configurare il compilatore TypeScript integrato in Visual Studio in modo che generi codice JavaScript ECMAScript6 oppure, se vogliamo generare codice ECMAScript5, utilizzare un compatibility shim adeguato. Se non sapete cos'è uno shim, consiglio di recuperare l'informazione leggendo questo articolo sul blog ufficiale Microsof TechNet. In poche parole, uno shim è una interfaccia software che è in grado di accettare un determinato set di comandi (nel nostro caso ES6) e fa in modo di gestirli in totale trasparenza tramite un altro set di comandi (nel nostro caso ES5), restituendo il medesimo output atteso. In altre parole, un layer di (retro)compatibilità che svolge per ECMAScript5 quello che un polyfill fa per un browser di vecchia generazione. La libreria migliore per svolgere questo ruolo è ormai da alcuni mesi la già citata core-js, che fornisce un supporto pressoché totale per i tipi nativi ECMAScript6.
  2. Assicurarci che il compilatore Typescript possa accedere ai Type Definition File delle librerie utilizzate, incluso l'eventuale compatibility shim. Con il termine Type Definition File (o Typings) si intendono quei file che descrivono i tipi utilizzati dal codice che il transpiler TypeScript integrato in Visual Studio dovrà compilare seguendo l'algoritmo di risoluzione modulare di Node.js (o altra strategia di risoluzione utilizzata): per maggiori informazioni su questo aspetto specifico, consiglio di leggere questo illuminante paragrafo contenuto all'interno della documentazione ufficiale TypeScript. E' importante considerare che il compilatore TypeScript fa già del suo meglio per recuperare i Type Definition File all'interno delle varie librerie utilizzate, guardando all'interno dei file   package.json  e/o index.d.ts presenti nella cartella principale di ogni libreria. Nella maggior parte dei casi questi file sono presenti, risolvendo di fatto qualsiasi problema di definizione: non è così per le librerie ancora in via di sviluppo, come appunto Angular2, e per quelle non appositamente pensate per essere utilizzate con TypeScript, come appunto core-js: in questi casi è necessario provvedere manualmente, altrimenti si incorrerà inevitabilmente negli errori di cui sopra.

Il mio problema era dovuto al fatto che, pur avendo svolto correttamente quanto descritto dal punto 1, non avevo considerato la necessità di fare anche quanto indicato dal punto 2. Nello specifico, avevo impostato il compilatore TypeScript per produrre codice ECMAScript5, cosa di per sé buona e giusta visto che mi interessava supportare anche browser di vecchia generazione: per questo motivo avevo anche incluso la libreria core-js tra i pacchetti NPM da scaricare, così da dotare il mio codice di tutti gli shim del caso. Quello che mancava erano i Typings di core-js, necessari per "informare" il compilatore TypeScript di Visual Studio che tutti i tipi ECMAScript6 utilizzati dalla nuova versione RC1 di Angular2 erano correttamente gestiti da una delle librerie presenti nel progetto (core-js) e quindi, banalmente, "potevano essere presi per buoni".

La Soluzione

Il problema, come detto, si può risolvere sostanzialmente in due modi: configurare il compilatore TypeScript per generare codice in ECMAScript6 oppure installare i Type Definition File della libreria core-js.

Metodo 1: Compilare in ES6

E' il workaround più semplice da implementare: è sufficiente aprire il file tsconfig.json  presente nella root del nostro progetto e modificare il valore della chiave target  da es5  a es6 . Questo è un esempio di file tsconfig.json  modificato in tal senso:

Ovviamente, questa scelta non è priva di inconvenienti: in questo modo non sarà possibile utilizzare strumenti, pacchetti NPM o librerie JS che non supportino ES6, come ad esempio la maggior parte dei tool di minifying/uglifying, primo tra tutti UglifyJS. Se non avete in programma di utilizzarli siete a posto, altrimenti converrà utilizzare il metodo successivo.

Metodo 2: Installare Typings e i Type Definition File di core-js

Il vantaggio di questo metodo è che vi consente di mantenere il target di generazione del codice JavaScript risultante in ECMAScript5, con indubbi vantaggi a livello di compatibilità. Prima di andare avanti, assicuratevi che il vostro file  tsconfig.json  sia grossomodo compatibile con queste impostazioni:

Aprite il file package.json  (utilizzato da Visual Studio per gestire i pacchetti NPM) e aggiungete, se non già presente, il pacchetto   typings  all'interno della chiave   dependencies  oppure  devDependencies . Fate lo stesso con la chiave scripts , a cui dovrete aggiungere una sotto-chiave postinstall  avente il seguente valore: typings install dt~core-js --global . Al termine del vostro intervento, il file dovrebbe avere una struttura analoga alla seguente:

In questo modo stiamo dicendo a Visual Studio di scaricare una versione aggiornata dello strumento typings  e di lanciarlo per scaricare i typings aggiornati di core-js a seguito di ogni aggiornamento dei pacchetti NPM. La prima esecuzione dello script avverrà nel momento in cui faremo click su Save: basterà attendere pochi istanti e una nuova cartella typings verrà aggiunta nella root della nostra applicazione, contenente i type definition file di core-js necessari per compilare opportunamente il codice ES6.

IMPORTANTE: Qualora i file tsconfig.json  e/o package.json  non fossero presenti nel vostro progetto potete crearli ex-novo, utilizzando le impostazioni predefinite ed applicando ad esse le modifiche indicate.

Per il momento è tutto: felice transpiling!

About Ryan

IT Project Manager, Web Interface Architect e Lead Developer di numerosi siti e servizi web ad alto traffico in Italia e in Europa. Dal 2010 si occupa anche della progettazione di App e giochi per dispositivi Android, iOS e Mobile Phone per conto di numerose società italiane. Microsoft MVP for Development Technologies dal 2018.

View all posts by Ryan

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *


Il periodo di verifica reCAPTCHA è scaduto. Ricaricare la pagina.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.