Introduction à TypeScript

De nos jours, le développement d’une application web peut difficilement se passer du langage Javascript. L’hégémonie de ce langage ne fait plus de doute et sa communauté est l’une des plus importantes dans le monde du développement web, ce qui est surement dû à sa flexibilité intrinsèque. Vous l’avez compris, dans cet article nous allons vous présenter TypeScript.
Nous présenterons dans un premier temps TypeScript et ses subtilités puis, dans un second temps, les fonctionnalités que ce langage apporte par rapport au Javascript. Nous aborderons ensuite ses différents concepts clés pour enfin finir par les avantages et les inconvénients ressentis au cours de son utilisation.
TypeScript : qu’est-ce que c’est ?
TypeScript est un langage de programmation développé par Microsoft en 2012. Son ambition principale est d’améliorer la productivité de développement d’applications complexes.
C’est un langage open source, développé comme un sur-ensemble de Javascript. Ce qu’il faut comprendre, c’est que tout code valide en Javascript l’est également en TypeScript.
Cependant, ce langage introduit des fonctionnalités optionnelles comme le typage ou la programmation orientée objet. Pour bénéficier de ces fonctionnalités, aucune librairie n’est requise. Il suffit d’utiliser l’outil de compilation de TypeScript pour le transpiler (compiler le code source d’un langage en un autre langage) en Javascript. Ainsi, le code exécuté sera un équivalent Javascript du code TypeScript compilé.
Pourquoi utiliser TypeScript ?
Si vous êtes un développeur Javascript, le langage TypeScript est du Javascript viable. Pour vous, Typescript est une JS linter dans le sens où, les contraintes demandées par TypeScript sont plus fortes que pour le Javascript.
Dans le cas des développeurs backend (C# ou Java), en apprenant le TypeScript vous vous évitez des erreurs simples remontées par le compilateur.
Les avantages et inconvénients d’utiliser TypeScript
Ci-dessous, j’ai recensé quelques avantages et inconvénients de l’utilisation du TypeScript sur un projet.
Les avantages de TypeScript
- Langage typé
- Compilation en différentes versions ECAMScript à partir de la version 3
- De nombreux outils sont disponibles
- Un langage orienté objet avec l’introduction du typage, de l’héritage ou encore les notions de public et private
- La transition du Javascript vers le TypeScript peut se faire progressivement par l’introduction au fur et à mesure de types
- La transition inverse très simple grâce à la transpilation en ECAMScript
Les inconvénients de TypeScript
- Le code exécuté doit être compilé au préalable
- Le code a une syntaxe plus lourde
- Les fichiers de déclaration des librairies ne sont pas toujours disponibles ou à jour
- TypeScript ne corrige pas les travers du JavaScript, il en limite certains impacts en amont
Comment utiliser TypeScript ?
Avant de construire votre projet en TypeScript, il faut d’abord l’installer, le configurer mais surtout comprendre les dépendances et maîtriser sa syntaxe.
Installation et configuration de TypeScript
Il existe deux possibilités pour installer les outils nécessaires pour TypeScript :
- Via l’outil npm en installant Node.js
- Via l’installation d’un plugin sur votre IDE (liste des IDE ayant un plugin)
Si vous avez Visual Studio 2015 Update 3, Visual Studio 2017 ou encore Visual Studio code, TypeScript est installé par défaut. Voici la commande à exécuter pour installer TypeScript avec NPM :
npm install -g typescript |
Ci-dessous, un code Javascript valide dans un fichier TypeScript, identifié par l’extension .ts.
Afin de pouvoir exécuter ce programme, il faut d’abord le compiler grâce à la commande suivante :
tsc greeter.ts |
Un fichier greeter.js sera alors généré dans le même dossier que le fichier greeter.ts.
À partir de là, il vous suffit de référencer le fichier Javascript dans la page html pour exécuter le programme.
Voilà, vous venez de créer votre première application en TypeScript ! Mais quelle différence y-a-t-il avec une application Javascript ? À ce stade, aucune ! Et c’est là l’une des forces de TypeScript.
En effet, étant donné que TypeScript est un sur-ensemble du Javascript, il peut être intégré de façon partielle dans un projet Javascript sans trop de difficulté.
Notre application en TypeScript est créée, penchons-nous maintenant sur la fonctionnalité phare du TypeScript : le typage statique.
Présentation des types de bases en TypeScript
Comme vous le savez peut-être, Javascript est un langage non fortement typé mais dynamique. Le type des données n’est identifié qu’à l’exécution du programme. On peut ainsi modifier le type des données à la volée au cours de l’exécution.
Comme le montre l’exemple ci-dessus, une même variable, au cours du programme, peut stocker tantôt un nombre, tantôt une chaîne de caractères ou enfin une fonction. Cela offre une grande flexibilité aux développeurs sur la manière de développer leur application. Le revers de la médaille de cette souplesse est qu’elle peut être la cause d’un nombre de bugs important lorsque le type des données est mal maîtrisé. Dès lors, la seule façon d’identifier les bugs est d’exécuter le code.
TypeScript introduit la notion d’un typage un peu plus fort que pour le langage Javascript. Ce typage se manifeste par l’ajout de plusieurs types de bases ainsi qu’un typage statique.
Rappelons qu’un langage est dit de typage statique quand celui-ci vérifie les types des variables à la compilation, alors qu’un langage dit de typage dynamique, effectue cette vérification à l’exécution.
La syntaxe du typage TypeScript
De façon générale, la déclaration de variables typées en TypeScript se fait de la manière suivante :
Dans l’exemple ci-dessus, les deux premières déclarations de variables sont typées explicitement et la dernière l’est implicitement. Notons également que certains IDEs peuvent vous aider à identifier le type de vos données assez facilement en survolant la variable qui stocke la donnée. Cette fonctionnalité est très pratique pour les projets volumineux, à condition de bien déclarer les types de façon explicite.
Le typage par déduction avec le compilateur TypeScript
C’est le mécanisme mis en place par le compilateur TypeScript pour identifier le type d’une variable. Lorsque le compilateur rencontre la première occurrence d’une variable, il va tenter d’en déduire son type par rapport à l’utilisation de la variable et donc supposer que toutes les autres occurrences de cette dernière auront le même type.
Boolean
Il s’agit d’un type de donnée qui définit une information comme étant vraie ou fausse.
C’est surement le type le simple. Vous pouvez le déclarer de deux façons :
Number
Ce type d’information définit un nombre soit de façons décimal (1234), hexadécimal (0x37CF), octal (0o377) et binaire (0b111001).
TypeScript stocke les nombres en variables flottantes comme en JavaScript.
let anInt: number = 6;
let decimal: number = 2.9; let hex: number = 0xa5d2; |
Les données de type binaires et octets sont également déclarées, le type number et ce depuis ECMAScript 2015.
let binary: number = 0b1010;
let octal: number = 0o762; |
String
Le type “string” définit une information sous la forme d’une chaîne de caractères.
Là encore, comme avec JavaScript, la variable de type string se déclare de la même façon. On peut utiliser de simples quotes, les doubles quotes et l’écriture par template avec les accents graves (Ctrl+Alt+7 ou Alt Gr +7 pour les claviers francophones).
Dans l’exemple suivant, on définit une fonction greeter qui attend un paramètre de type string et qui retourne une valeur de type string.
Lorsque l’on tente d’utiliser la fonction greeter avec un paramètre de type number, voici le message d’erreur que l’on reçoit lors de la compilation.
greeter_string.ts:9:56 – error TS2345: Argument of type ‘number’ is not assignable to parameter of type ‘string’.
9 document.getElementById(“display”).innerHTML = greeter(thisYeah); |
A noter : ce retour est très souvent proposé à la volée par les IDEs supportant le TypeScript.
Array
Encore une subtilité, l’écriture du JavaScript est entièrement reprise en TypeScript. Du fait qu’il existe cette notion, il est possible de déclarer un array d’un type spécifique en ajoutant des crochets“[ ]” juste après le nom du type. Ou encore, il est possible d’utiliser une écriture générique, le type générique Array.
var names: string[] = [“Pierre”,”Paul”,”Jaques”];
var otherNames: Array<string> = [“Pierre”,”Paul”,”Jaques”]; |
Any
Ce type est particulier. C’est le type qui se rapproche le plus du typage dynamique du Javascript. En effet, n’importe quel autre type de données peut être affecté à une variable de type any. Ce type est particulièrement pratique dans le cas d’utilisation de librairie tierce où il n’existe pas de fichier de déclaration mais aussi dans le cas d’appels ajax.
Void
Ce type est souvent utilisé pour déclarer le type de retour d’une fonction qui ne renvoie rien. Bien qu’il soit possible d’avoir une variable de type void, je n’ai pas eu l’occasion d’utiliser ce type dans ce cas-là.
Enum
C’est la petite nouveauté sympa ! Le type enum permet d’écrire de façon plus lisible des données numériques et d’en comprendre le sens rapidement. Cela évite d’avoir des valeurs magiques un peu partout.
La syntaxe de enum est la même que celle du c#.
Par défaut, la première valeur de l’enum sera 0, toutefois il est possible de préciser la valeur de chaque élément de l’enum.
En survolant le nom de la valeur de l’enum avec le curseur il est possible de voir sa valeur numérique réelle.
Le casting explicite de TypeScript
Dans les langages fortement typés, on a parfois besoin d’expliciter le type d’un objet. C’est là que le casting entre en jeu. Pour cette opération, TypeScript propose deux syntaxes :
- la première consiste à ajouter anydevant la variable de type souhaité entre les symboles “<” et “>”,
- la seconde consiste à faire précéder la variable par le mot-clé “as” suivi du type souhaité :
var myOtherObject = {id:2, name:”Peter”} as any; |
Attention toutefois à ne pas trop abuser du casting en “any”, car il peut très vite conduire aux travers liés au type du JavaScript mentionné un peu plus tôt.
Les fonctions dans TypeScript
Les fonctions dans TypeScript s’écrivent quasiment de la même façon que dans Javascript avec les types.
Reprenons la fonction greeter évoquée précédemment.
En analysant rapidement cette fonction, on peut constater qu’elle accepte en paramètre une chaîne de caractères et retourne également une chaîne de caractères. Nous pouvons dès lors intégrer ces caractéristiques dans la signature de la fonction de la façon suivante :
Dans le cas où notre fonction aurait des paramètres optionnels, il suffit d’ajouter après le nom du paramètre un point d’interrogation.
Il est possible d’obtenir le même résultat avec des paramètres initialisés, ce qui donne :
Interface de TypeScript
L’interface nous offre un mécanisme permettant de définir des conditions (propriétés et/ou méthodes) requis pour un objet.
Cette interface est une représentation simplifiée d’une personne. Pour qu’un objet satisfasse cette interface, il doit contenir au moins toutes les propriétés et méthodes de cette interface.
Ci-dessous, se trouve un exemple d’utilisation avec la méthode greeter qui accepte en paramètre uniquement les objets respectant l’interface “IPerson”.
Si l’objet ne respecte pas l’interface, alors le compilateur indiquera les éléments manquants. Ici la propriété “lastname” n’est pas définie.
Pour pouvoir utiliser la variable “invalidPerson”, il est possible de compléter la définition de la variable ou modifier l’interface en rendant la propriété “lastname” optionnelle en ajoutant un point d’interrogation après le nom de la variable, comme ci-dessous.
interface IPerson{
firstName: string; lastName?: string; } |
Les classes dans TypeScript
La classe est la notion qui définit un objet, elle est l’un des concepts clés de la programmation orientée objet avec l’interface. Ces dernières sont utilisées en tandem au travers de structures appelées “design pattern” dont l’objectif est de résoudre des problèmes spécifiques.
Ci-dessous un exemple de classe :
Dans cet exemple nous avons défini une classe “Personnage”. Pour accéder aux variables de classe, on utilise le mot-clé “this”.
Les modules de TypeScript
Un module est ce qu’en .NET on appellerait une assembly ou namespace. C’est un regroupement logique de classes et d’interfaces qui permet de structurer un projet et de le rendre plus propice aux changements.
Le module se déclare à l’aide du mot-clé “module”. Ci-dessous un exemple de déclaration et d’utilisation d’un module simple.
Ici, la méthode “greeting” sans paramètres est accessible dans toute l’application au travers de Module1 alors que la méthode “greeting” avec paramètres n’est accessible que dans le fichier où elle est déclarée. Le module s’utilise comme suivant :
Les modules peuvent aussi bien exposer des classes que des fonctions, des constantes ou des interfaces.
Les fichiers de déclaration
C’est le fichier qui contient l’ensemble des signatures de méthode d’une librairie. Il permet entre autres, d’alimenter l’auto-complétion et surtout d’avoir rapidement l’API complète d’une librairie. Il n’est donc plus nécessaire de connaître par cœur l’API des librairies.
La source principale des fichiers de déclaration se trouve dans ce repository git : https://github.com/DefinitelyTyped/DefinitelyTyped. Vous y trouverez un très grand nombre de fichiers de déclaration des librairies connues. Sachez que ces fichiers de déclaration sont mis à jour par la communauté, il peut donc y avoir des décalages entre la version de la librairie et celle du fichier de déclaration.
Ici, nous souhaitons utiliser lodash ainsi que le fichier de déclaration associé dans notre application que nous installons grâce aux commandes ci-dessus. Notez la différence de version entre la librairie et le fichier de déclaration.
L’installation du fichier de déclaration permet de bénéficier de l’auto-complétion, ce qui est plutôt pratique lorsque l’on travaille avec des grosses librairies. Si vous recherchez le fichier de déclaration d’une librairie, vous pouvez utiliser le site suivant : https://aka.ms/types
Cas d’utilisation d’un code legacy Javascript en TypeScript
De la même façon, il est possible de commencer à utiliser du TypeScript sur un projet en JavaScript. Pour cela, il suffit de créer les fichiers TypeScript dans un dossier à part et de les compiler dans votre dossier de déploiement. Si des interactions sont nécessaires entre les fichiers en TypeScript et en JavaScript, alors on peut envisager l’utilisation d’un fichier de déclaration de type spécifique pour notre code JavaScript.
Ci-dessous un exemple simple d’un code TypeScript qui utilise du code legacy en JavaScript.
- legacy.js contient notre code legacy
- App.ts contient notre nouveau code TypeScript
- Legacy-typing.d.ts contient la définition des types de l’ensemble des éléments que l’on souhaite utiliser dans notre TypeScript
La première ligne référence le fichier de déclaration qui contient la définition de LegacyGreeter.
On déclare un module dans lequel on définit une interface de correction aux éléments que l’on souhaite utiliser pour du code legacy. Puis on déclare une variable globale du même type que l’interface que l’on a définie dans notre module.
Ci-dessus, le code legacy qui sera appelé lors de l’exécution.
De cette façon, le TypeScript peut évoluer sans modifier le JavaScript, ce qui permet une migration plus maîtrisée du JavaScript au TypeScript.
Gagner du temps grâce à TypeScript
TypeScript est un langage qui permet de raccourcir le temps de développement en introduisant des fonctionnalités de la programmation orientée objet. Le compilateur est d’une aide précieuse pour repérer rapidement les erreurs car il réduit le délai entre l’écriture du code et l’identification d’erreurs grâce notamment au typage.
À noter que le transpilage du TypeScript en JavaScript peut réduire la barrière à l’entrée de l’usage de langage script pour des développeurs backend, délègue la gestion des subtilités du JavaScript aux outils et assure un contrôle sur la compatibilité de l’application avec les différents navigateurs sous condition.
Et pour aller plus loin, nous vous invitons à découvrir notre article sur les fonctions de TypeScript.