On se rend compte que dans les applications web moderne la place qu’occupe JavaScript devient de plus en plus importante. Mais JavaScript est un langage difficile, par de nombreux aspects assez exotiques, fondé sur des préconisations anciennes. On en est actuellement à ES5 publié en 2009 et maintenant pris en charge par la majorité des navigateurs.
ES6 qui a été renommé ES2015, a été publié en 2015 et il faudra encore du temps pour que tous les navigateurs l’implémentent. Pour avoir une idée de la situation regardez ce tableau. Désormais il devrait y avoir une publication annuelle et donc cette année on verra sortir un ES2016.
Donc actuellement pour être lisible par tous les navigateurs nos scripts doivent s’en tenir à l’ES5 et c’est dommage parce qu’il y a plein de bonnes chose dans l’ES6 ! Par exemple on pourra enfin créer de vraies classes avec le mot-clé class, on aura une gestion améliorée des tableaux, des promises…
Le futur c’est bien mais on code aujourd’hui alors comment faire ? C’est là qu’intervient TypeScript et justifie bien une série d’articles sur le sujet. En gros TypeScript nous offre une syntaxe riche à la hauteur des standards actuels et compile tout ça en JavaScript compréhensible par tous les supports (par exemple ES5) !
Il y a d’autres outils qui ont le même objectif, comme CoffeeScript ou Dart. Mais il me semble que TypeScript s’en sort bien mieux. D’autre part il accepte totalement la syntaxe JavaScript, il se contente d’ajouter d’autres possibilités. Autrement dit un code classique en JavaScript est valide pour TypeScript.
Le site de référence de TypeScript est ici.
Les défauts de JavaScript et ce que TypeScript apporte
Il y a un certain nombre de choses qu’on peut repprocher à JavaScript :
- les prototypes : franchement j’ai régulièrement besoin de me replonger dans les bases parce que ce n’est pas du tout intuitif comme style de programmation même si c’est une approche objet tout à fait valide. TypeScript nous offre quelque chose de plus classique et répandu : des classes, des interfaces, des modules.
- les types : JavaScript n’est pas typé, on entre ce qu’on veut dans une variable et il décide de quoi il s’agit. Lorsqu’on effectue certaines opérations le type change pour s’adapter. C’est très souple mais aussi plein de surprises ! TypeScript propose un contrôle des types.
- les modules : si vous avez déjà réalisé une application JavaScript un peu volumineuse vous avez forcément été confronté au problème de l’organisation du code. TypeScript normalise le chargement des modules.
Installation et utilisation
Pour installer TypeScript le plus simple est d’utiliser node.js. Il permet de faire tourner du JavaScript n’importe où et pas seulement dans un navigateur, par exemple sur un serveur. Dans le contexte de TypeScript on va utiliser node.js pour la compilation. Si vous ne savez pas si vous l’avez déjà installé il suffit d’utiliser cette commande :
npm –v
S’il est installé vous obtenez le numéro de version. S’il n’est pas installé utilisez le gestionnaire de package npm ainsi :
npm install -g typescript
Et pour compiler le code il suffit d’utiliser la commande tsc :
tsc monfichier.ts
On se retrouve alors avec un fichier monfichier.js en pur JavaScript.
Si comme moi vous n’êtes pas un grand fan de la console vous pouvez ajouter un plugin à votre éditeur ou IDE favori. Par exemple il existe un superbe plugin pour Sublime Text.
Une fois le plugin installé dans Sublime Text il suffit de créer un fichier avec du code TypeScript (suffixe ts). Prenons le code d’exemple du site officiel :
On voit que Sublime Text a reconnu le type de fichier. Il suffit maintenant d’utiliser la touche F7, on me demande si je veux entrer des paramètres de compilation :
Comme je n’en veux pas j’utilise la touche Entrée. La compilation se déroule et quand c’est fini j’ai ce message :
Et maintenant j’ai un nouveau fichier :
Le code est le même parce qu’au départ il n’y a que du code JavaScript standard.
Le plugin ne fait pas que de la compilation, vous avez tous les renseignements sur la page GitHub.
Si vous n’aimez pas Sublime Texte vous pouvez utiliser Atom, Eclipse, WebStorm… Et évidemment puisque TypeScript a été créé par Microsoft toues les versions de Visual Studio dont le plus léger est Visual Studio Code.
Vous disposez en plus d’un éditeur en ligne bien pratique pour vos essais sur le site de TypeScript :
Vous avez donc tout ce qu’il faut pour jouer avec TypeScript, alors allons voir ce qu’il nous propose !
Déclaration des variables
Classiquement la déclaration d’une variable dans JavaScript se fait avec var. L’inconvénient c’est que la variable est visible en dehors du bloc dans lequel elle est définie, ce qui peut créer des bugs difficiles à traquer. On s’en sort généralement en utilisant une fermeture (closure) mais c’est un peu lourd pour un simple inconvénient.
ES6 (et donc TypeScript) introduit let qui arrange élégamment l’affaire. Avec lui la variable n’est visible que dans le bloc où elle est créée.
Considérez cet exemple :
var say = "coucou"; var outer = "Une variable externe"; if (say === "coucou") { var say = "au-revoir"; console.log(say); console.log(outer); var inner = "Une variable interne"; console.log(inner); } console.log(say); console.log(inner);
Voici ce qu’on obtient dans la console :
au-revoir Une variable externe Une variable interne au-revoir Une variable interne
On voit que la variable interne inner est accessible à l’extérieur du bloc où elle est définie.
Remplaçons var par let :
let say = "coucou"; let outer = "Une variable externe"; if (say === "coucou") { let say = "au-revoir"; console.log(say); console.log(outer); let inner = "Une variable interne"; console.log(inner); } console.log(say); console.log(inner);
Si j’utilise ce code dans FireFox je tombe maintenant sur cette erreur :
ReferenceError: inner is not defined
Mais je ne me rends compte du problème qu’à l’exécution. Utilisons maintenant TypeScript et lançons une compilation :
J’ai une alerte immédiate et je peux corriger mon code. Toutefois le fichier JavaScript est quand même généré :
var say = "coucou"; var outer = "Une variable externe"; if (say === "coucou") { var say_1 = "au-revoir"; console.log(say_1); console.log(outer); var inner = "Une variable interne"; console.log(inner); } console.log(say); console.log(inner);
Pour la compatibilité je me retrouve avec des var et évidemment le même souci, mais comme j’ai eu l’alerte j’ai pu corriger mon code. Par contre remarquez le renommage de la variable interne say en say_1.
Il existe aussi const qui est identique à let mais il est impossible de changer ensuite la valeur puisque c’est une constante.
Le typage
Avec JavaScript on peut écrire ce genre de code :
let a = 6; let b = '7'; console.log(a * b);
Et on obtient le résultat :
42
Pourtant au départ la variable b contient une chaîne de caractères, mais JavaScript est souple avec les types et ensuite il transforme a en nombre.
La souplesse c’est bien mais ça peut conduire à faire n’importe quoi ou à tomber sur des problèmes pas forcément faciles à détecter et à résoudre.
Si on compile ce code avec TypeScript il l’aime pas du tout :
error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.
Il va quand même générer le fichier JavaScript mais vous êtes prévenu.
Avec JavaScript vous pouvez changer de type sans problème :
let a = 6; a = '7'; console.log(a);
Si vous compilez ce code avec TypeScript il ne va pas non plus l’aimer :
error TS2322: Type 'string' is not assignable to type 'number'.
Les types
JavaScript n’a pas de typage structurel mais TypeScript ajoute un système optionnel d’annotations pour obtenir un langage fortement typé, comme les langages classiques. Par exemple vous pouvez écrire :
let a: number = 6;
Là vous signifiez clairement que vous voulez un nombre, il vous sera par la suite interdit d’assigner un autre type. De la même manière vous avez les classiques :
- boolean
- string
Les tableaux
Pour un tableau vous ajoutez les crochets, par exemple :
let tableau: number[] = [0, 8, 13];
Un peu plus exotique est le Tuple :
let x: [boolean, number];
Vous imposez le type des éléments.
Les énumérations
Un nouveau type intéressant est enum :
enum Metier {'Soudeur', 'Journaliste', 'Banquier'}; let a: Metier = Metier.Journaliste; console.log(a);
Par défaut le premier l’index commence à 0. Ici a aura donc la valeur 1. Il est intéressant de voir comment cela est traduit en JavaScript :
var Metier; (function (Metier) { Metier[Metier['Soudeur'] = 0] = 'Soudeur'; Metier[Metier['Journaliste'] = 1] = 'Journaliste'; Metier[Metier['Banquier'] = 2] = 'Banquier'; })(Metier || (Metier = {})); ; var a = Metier.Journaliste; console.log(a);
L’énumération est traduite en objet. C’est quand même plus court avec TypeScript !
On peut changer la valeur d’origine :
enum Metier {'Soudeur' = 2, 'Journaliste', 'Banquier'}; let a: Metier = Metier.Journaliste; console.log(a);
Là du coup a aura la valeur 3.
Les type any et union
Mais des fois on ne sait pas quel type ce sera, alors on peut utiliser any. Par exemple pour un tableau avec des types quelconques :
let list: any[] = ['toto', false];
On peut aussi imaginer un paramètre de fonction qui peut accepter plusieurs types :
function traitement(valeur: any) { if (typeof valeur === "number") { return valeur * 2; } else if (typeof valeur === "boolean") { return !valeur; } }
Mais que se passe-t-il si je passe par exemple une chaîne de caractères ? Je peux évidemment renvoyer une erreur, mais je peux aussi utiliser le type union :
function traitement(valeur: number | boolean) {
Pratique non ?
Dans un prochain article je montrerai l’approche objet de TypeScript.