Typescript
Javascript est un langage puissant, mais il est très permissif. C'est-à-dire, si on ne fait pas attention, le risque d'erreur est assez élevé. Considérez l'exemple suivant :
// Affecter des types différentes aux variables est autorisé
let a = "hello";
a = 3;
console.log(a);
// Les objets ne sont pas strictement définis
const response = {
greeting: "Hello",
audience: "World",
number: 123
}
// On peut augmenter un objet sans problème
response.d = 567;
// Remanier le code est plus compliqué ?
// Ici, on voulais dire `greeting` ? Ou ajouter une nouvelle clé `greetingg` ?
response.greetingg = 5;
// Pas de validation des données avant l’exécution
var request;
const body = request.body;
// ... et si address était null ? Exception !
if (body.address.city === "Paris") {
}
Il est gérable pour les petits projets, mais dès que l'on dépasse un certaine grandeur, il devient impossible à gérer :
Remanier le code est compliqué et risqué
Pas de signe d'erreurs avant de lancer un test
Manque de rigueur dans les types des données ou la structure des objets
En plus, JS est un langage qui évolue constamment, avec des niveaux de support hétérogène sur le marché. Pour écrire du code qui fonctionne partout, on est obligé de viser une version (norme) précise (ECMA 2015, par exemple), qui veut dire qu'un grand nombre de fonctionnalités modernes ne sont pas disponibles.
Avant, on devait utiliser ce qu'on appelle un "transpiler", qui va convertir des fonctions modernes en leurs équivalents dans les anciennes versions (souvent des fonctions qui remplacent un feature), et tout devenait très compliqué avec des "shims" et des "polyfills" (enduit de rebouchage) pour remplir ces trous.
Chez Microsoft, ils ont développé TypeScript, un superset de JS qui permet d'imposer des types stricts sur JS, et régler une grande partie des problèmes JS vanilla.
Javascript est Typescript, mais Typescript n'est pas Javascript !
Typescript apporte le typage strict (comme présent dans d'autres langages comme Java, C#, etc) à Javascript. Le compilateur (et éventuellement l'IDE) va signaler :
L'utilisation des variables non déclarés
L'utilisation des types non autorisés dans les fonctions
Détecter l'utilisation des fonctions non-existants, ou des erreurs parmi des paramètres
... etc
En réalité, Typescript exige une étape de transpilation dans laquelle le Typescript est transformé en Javascript vanilla. Pendant cette procédure, des erreurs sont détectées et signalées au développeur.
Activer Typescript sur un projet NodeJS
Installez le package typescript
, en développement seulement (car notre code final serait du JS transpilé)
npm install -g typescript --save-dev
Ceci installe typescript comme dépendance nécessaire pour transpiler notre projet, et sera nécessaire quand on commence à créer nos images Docker pour production.
Ensuite, on initialise typescript sur notre projet :
tsc --init
Ce script nous crée un fichier tsconfig.json
qui contient toutes les options pour la compilation de typescript vers javascript, par exemple :
target
: la version cible de la compilation javascript. Typescript va automatiquement convertir tout vers cette version-là.outDir
: l'endroit où il faut créer les fichiers .js
En effet, outDir
n'est pas précisé par défaut. On va spécifier le dossier build
.
tsconfig.json
"outDir": "./build", /* Specify an output folder for all emitted files. */
On peut ensuite compiler notre code en javascript avec la commande suivante dans l'invite de commandes :
tsc
Dans le dossier build
, il y aura donc un fichier .js pour chaque fichier .ts dans notre dossier src
.
Si on lance tsc
maintenant, on aura une erreur, parce qu'on n'a pas encore de fichiers de type .ts
dans notre projet.
Mon premier fichier TypeScript
Créez un fichier .ts
sous src
, nous allons expérimenter avec des types :
console.log("This is my first Typescript file");
// A noter, on précise les types par : [string|number|boolean|any ou autres]
const prenom: string = "Kevin";
const nom: string = "Glass";
const age: number = 40;
const etudiant: boolean = false;
// A noter, on précise le type des paramètres aussi
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet(prenom, new Date());
// Définir une "interface" qui est une définition d'un objet
interface IRequest {
type: 'POST' | 'GET'; // On peut énumérer des valeurs possibles
orderBy?: string; // Un point d’interrogation rend le champ optionnel
limit?: number;
page?: number;
}
const req: IRequest = {
type: 'POST',
orderBy: 'title',
page: 1
}
// On peut définir explicitement des types
type ActionState = 'pending' | 'busy' | 'done' | 'canceled';
const state: ActionState = 'done';
/*
On peut définir des types pour les fonctions
Dans cet example, le callback passe un ActionStates comme paramètre et attend un retour de type IRequest
*/
type CallbackFunction = (state: ActionState) => IRequest;
const SendRequest = (cb: CallbackFunction) => {
const req = cb('pending');
// ... envoyez la requête
}
SendRequest(
(state) => {
return {
type: (state === 'pending' ? 'POST' : 'GET'),
page: 1
}
}
)
On transpile ce script avec :
tsc
Regardez dans le répertoire build
, vous verrez un fichier myfirsttypescript.js
. Il y a quelques points à remarquer :
Toutes les définitions et les expressions non
js
ont disparuesNos commentaires existent toujours
Essayez d'introduire des erreurs suivantes :
Utiliser une variable sans le déclarer
Affecter un string à une variable de type numéro
Passer un mauvais paramètre
Downleveling le target
dans tsconfig.json
target
dans tsconfig.json
Pour voir en action la transpilation, changez la target
dans tsconfig.json
à es3
, et ré-exécutez tsc
. Vous allez remarquer :
console.log("Hello ".concat(person, ", today is ").concat(date.toDateString(), "!"));
Pourquoi ? Parce que les templates ne sont pas encore supportés en es3
, et donc on est obligé de le transpiler autrement.
Remettez la valeur d'avant dans tsconfig.json
.
Options de transpilation
À la fin de tsconfig.json
, il y a une gamme d'options qui rendent de plus en plus stricte notre système de typage.
Exécution automatique avec ts-node
et nodemon
ts-node
et nodemon
La librairie typescript
est utile pour la compilation de notre code en JS, mais en développement il est fatiguant de toujours recompiler manuellement notre code.
En plus, on voit que les numéros de ligne dans le JS compilé ne correspondent plus aux lignes dans le .ts
, qui pourrait perturber aussi les messages d'erreur en exécution (call-stack).
Pendant le développement, nous utilisons un autre outil ts-node
qui est l'équivalent de node
sauf, on peut exécuter directement les fichiers typescript.
npm install ts-node --save-dev
sudo npm install -g ts-node
Maintenant, on peut directement lancer un script .ts :
ts-node src/typescript/myfirsttypescript.ts
Ou bien, on peut en créer une entrée dans package.json
:
"scripts": {
...
"ts-example": "nodemon --watch 'src' src/myfirsttypescript.ts"
}
On peut donc lancer simplement notre script en utilisant npm :
npm run ts-example
Dernière mise à jour