TypeScript - 1/3 : Présentation

typescript-logo

Première partie du dossier TypeScript

Le langage TypeScript est l'une des technologies les plus appréciées de ces dernières années, dans le développement Frontend comme dans le Backend. Sa popularité ne cesse de croître et il est au cœur de nombreux projets : Angular, NativeScript, Ionic, VS Code, Apollo GraphQL, Babylon.js, RxJS, Nest, TypeORM, etc.

Il n'existe à l'heure actuelle aucune alternative, même si certaines technologies partagent des objectifs communs ou proposent des avantages similaires. C'est le cas de Flow, le type checker développé par Facebook, ou (plus éloigné) du langage elm.


Présentation

"JavaScript that scales."

TypeScript est un langage open source, créé par Microsoft, transpilable en JavaScript. Pour l'anecdote, on retrouve Anders Hejlsberg, créateur de C# (entre autres), derrière le projet.

Ses principaux objectifs sont :

  • Le support des propositions existantes et à venir d'EcmaScript.
  • L'apport du typage optionnel à JavaScript.
  • L'identification anticipée (static) de codes potentiellement invalides.
  • La compilation vers du JavaScript optimisé, avec pour cible, au choix: ES3, ES5, ES6...

Ce que TypeScript n'ambitionne pas de faire, entre autres :

  • Imiter les langages existants; mais plutôt exploiter la nature de JavaScript et les usages des développeurs comme guide pour rendre le langage pertinent
  • Utiliser un système de types "sage" (sound) :

Le système de types de TypeScript n'est pas "sage", ce qui signifie qu'il autorise certaines opérations qui ne peuvent être vérifiées au moment de la compilation (plus d'informations ici : "A Note on Soundness"). C'est l'une des grandes différences majeures avec Flow, comme expliquée par James Kyle sur le forum de React.

Pour être en mesure d'exécuter les lignes de commande citées dans la suite de l'article, installez typescript :

npm install -g typescript  

"Superset" et Transpilation

Entrons dans le vif du sujet : "TypeScript est un superset de JavaScript", c'est la punchline popularisée par Microsoft et partagée par de nombreux enthousiastes. Un superset apportant le typage, les interfaces, les énumérations, les types génériques, les décorateurs...
Si vous avez déjà lu des articles sur le langage, vous avez certainement aperçu un graphique similaire :

typescript-superset

Il n'est pas totalement faux, mais à nuancer. En effet, avec l'option allowJs, Le compilateur TypeScript (tsc) accepte le code JavaScript en entrée et produit du code transpilé (selon les paramètres fournis) en sortie.

Un code passé en entrée :

// person.js
class Person {  
  constructor(firstName) {
    this.firstName = firstName;
  }
}

console.log(new Person('John')); // Person { firstName: 'John' }  

Sa compilation (ou plutôt, transpilation) :

$ tsc --allowJs person.js --outDir dist

Le résultat ainsi transpilé, avec l'option target à "es5" (valeur par défaut) :

// dist/person.js
var Person = /** @class */ (function () {  
    function Person(firstName) {
        this.firstName = firstName;
    }
    return Person;
}());
console.log(new Person('John')); // Person { firstName: 'John' }  

Remarquez la lisibilité du code généré.

Par contre, si l'on renomme person.js (contenant notre code ES6) en person.ts, la compilation n'est plus possible :

$ tsc person.ts

person.ts(3,10): error TS2339: Property 'firstName' does not exist on type 'Person'.

Le fait de passer ce fichier en tant que code TypeScript (et non JavaScript) à tsc fait échouer la transpilation. Le compilateur s'attend à analyser du code TypeScript valide. Ce code n'est pas du TypeScript valide, bien qu'il soit du JavaScript valide.
Par conséquent, la notion de "Superset" telle que vulgarisée par le graphique des 3 ensembles est imprécise : on ne peut pas considérer ES6 comme un sous-ensemble de TypeScript.

Une syntaxe TypeScript valide, parmi d'autres :

// person.ts
class Person {  
  constructor(public firstName) {}
}

console.log(new Person('John')); // Person { firstName: 'John' }  

en utilisant firstName comme une parameter property (fonctionnalité de TypeScript abordée et "babelisée" sur ce blog). Sinon, il est nécessaire de déclarer firstName comme une class property et de l'affecter manuellement dans le constructeur.
La transpilation de ce code TypeScript produit le même code ES5 vu précédemment dans dist/person.js.


Pourquoi l'adopter ?

À suivre dans la deuxième partie du dossier.