TypeScript è un sovrainsieme di JavaScript. Il suo compito è quello di generare codice JavaScript effettuando una verifica interna sulla coerenza dei dati.

TypeScript di fatto non effettua una compilazione del codice nel senso tradizionale del termine ma piuttosto una sua trasformazione nel codice JavaScript di destinazione. Quello che TypeScript aggiunge a JavaScript è la verifica sul tipo di dati in uso.

Infatti TypeScript aggiunge a JavaScript la tipizzazione rigorosa comune a linguaggi come Java e C#. In altre parole se una variabile viene definita di tipo string o una funzione viene concepita per restituire un output di tipo number, TypeScript solleverà un errore e non genererà il corrispondente file JavaScript se i dati non manterranno la loro coerenza di tipo.

let a : string = 'Hello';
a = 1; // Errore

Fondamentale in TypeScript è la configurazione dell'interprete fornita tramite il file tsconfig.json creato nella directory di lavoro.

{
  "compilerOptions": {
      "baseUrl": "./src",
      "outDir": "./dist",
      "noEmitOnError" : true,
      "target": "es2017"
  }
}

In questo caso abbiamo specificato come directory dove cercare i file TypeScript (.ts) la directory src, come directory di destinazione dei file JavaScript (.js) la directory dist, abbiamo impedito di generare i file JavaScript in caso di errore ed infine abbiamo specificato la versione di JavaScript in cui verrà scritto il codice di output (qui è ECMAScript 2017).

Questo punto è decisivo per capire il vantaggio di fondo che offre TypeScript: possiamo infatti scrivere un codice TypeScript assolutamente moderno ed in linea con gli standard attuali e quindi avere un codice finale retrocompatibile semplicemente cambiando il valore della proprietà target.

Dato infatti il seguente codice TypeScript:

 class Person {
    constructor(private name: string, private job: string) {

    }
    public getName() : string  {
        return this.name;
    }
    public getJob() : string {
        return this.job;
    }

    public setName(n: string) : void {
        this.name = n;
    }

    public setJob(j: string) : void {
        this.job = j;
    }
}

let Gabriele : Person = new Person('Gabriele', 'developer');
console.log(Gabriele.getName() + ' is a ' + Gabriele.getJob());

Cambiando il valore della proprietà target in es5 (ECMAScript 5), avremo il seguente codice:

var Person = /** @class */ (function () {
    function Person(name, job) {
        this.name = name;
        this.job = job;
    }
    Person.prototype.getName = function () {
        return this.name;
    };
    Person.prototype.getJob = function () {
        return this.job;
    };
    Person.prototype.setName = function (n) {
        this.name = n;
    };
    Person.prototype.setJob = function (j) {
        this.job = j;
    };
    return Person;
}());
var Gabriele = new Person('Gabriele', 'developer');
console.log(Gabriele.getName() + ' is a ' + Gabriele.getJob());

Come si può notare, nel codice retrocompatibile finale sono stati eliminati tutti i riferimenti alla sintassi moderna delle classi JavaScript e quelli relativi alla coerenza di tipo e alla visibilità dei metodi e delle proprietà della classe originaria e della variabile di istanza.

In definitiva non solo è possibile scrivere codice retrocompatibile con le vecchie versioni di Node, ma anche condividere specifici componenti del backend con il frontend dei nostri siti ed applicazioni.