Barista part III

Typescript et ses fonctionnalités

Le cycle Barista utilise le langage Typescript, toutefois jusqu’ici nous n’avons que très peu utilisé ce langage à bon escient. En effet, nous avons codé comme si nous étions sous Javascript, il est temps que cela cesse !

Cependant, il est probable que vous ne soyez pas encore à l’aise avec Typescript. Pourquoi l’utiliser ? Quels avantages apporte-t-il ? Comment l’utiliser ? Vous aurez bientôt toutes les réponses à ces questions.

Typescript, c’est quoi ?

Typescript est un langage de programmation libre et open source développé par Microsoft qui a pour but d’améliorer et de sécuriser la production de code Javascript. C’est un sur-ensemble de Javascript (c’est-à-dire que tout code Javascript correct peut être utilisé avec Typescript). Le code Typescript est transpilé en Javascript, pouvant ainsi être interprété par n’importe quel navigateur web ou moteur Javascript.

Typescript permet un typage statique optionnel des variables et des fonctions, la création de classes et d’interfaces, l’import de modules, tout en conservant l’approche non-contraignante de Javascript. Il supporte la spécification ECMAScript 6.

Installer Typescript

Même si Typescript est déjà installé au sein du projet Barista, il est possible que vous souhaitiez l’utiliser en dehors de ce projet, voici la marche à suivre afin de procéder à son installation.

Typescript n’est pas un langage directement disponible sur le système, il n’est pas non plus interprété directement au sein du navigateur, comme Javascript. Pour l’utiliser, nous avons besoin de l’installer sur la machine.

Il existe deux façons d’installer Typescript:

  • En installant Visual Studio et le plugin Typescript
  • En passant par le gestionnaire de paquets de node.js, npm
#Permet d'installer Typescript au sein du projet courant
#(dans le dossier node_modules)
npm install typescript

#Ou alors, on peut utiliser la méthode suivante qui permet d'installer
#Typescript de façon globale sur la machine
npm install -g typescript

#Puis taper la commande suivante pour obtenir le numéro de version 
tsc -v

La transpilation

À ne pas confondre avec « transpiration » (bon j’étais obligé de la faire). La transpilation (ou transcompilation) est en fait une étape que l’on pourrait qualifier de pseudo-compilation + traduction. Je m’explique, en gros, le principe de base d’un compilateur est d’analyser votre code source, d’opérer tout un tas de vérifications etc. Pour finalement traduire le code en langage machine (le fameux code binaire).

Typescript fonctionne à l’aide d’un programme nommé tsc qui fait la même chose, à ceci près qu’il ne traduit pas le code en binaire, mais en Javascript! C’est pour ça que l’on dit que Typescript n’est qu’un sur-ensemble de Javascript, en vérité à la fin tout est retraduit en Javascript.

Ce qui signifie que:

  • Typescript n’apporte que du sucre syntaxique à Javascript.
  • Les possibilités de Typescript ne peuvent aller au delà des capacités de Javascript (puisqu’à la fin on transpile tout vers du Javascript.
  • Tout code Javascript ES6+ est un code Typescript valide.

Pour transpiler il vous suffit d’ouvrir un terminal et de taper la commande suivante:

# Ici on transpile le fichier monfichier.ts et l'on 
# obtient ainsi un fichier équivalent, traduit en javascript
tsc monfichier.ts

Maintenant que l’on a bien compris ce qu’est Typescript, passons à la suite.

Le typage de données

Typescript doit son nom à l’une de ses fonctionnalités les plus utiles, à savoir le support du typage statique de données. Le typage statique, contrairement au typage dynamique (qui est aussi supporté) permet d’effectuer ce que l’on appelle du type checking à la compilation.

En gros, tsc va vérifier, comme le ferait un compilateur C ou C++, que les données que l’on manipule correspondent bien aux types de données déclarés. Ce qui nous évite de découvrir ce genre d’erreurs une fois le programme lancé.

Par défaut, Javascript est un langage compilé à l’aide d’un JIT (Just In Time compiler), ce qui signifie qu’un morceau de code n’est analysé par le moteur Javascript (V8 par exemple) que lorsqu’on en a besoin et pas avant. C’est pour cela que la plupart des erreurs en Javascript sont perçues à l’exécution et non pas avant, car le programme n’est pas compilé en entier dès son chargement mais petit à petit.

Le fait de laisser un outil comme tsc vérifier le type de données revient à faire le boulot de la JIT mais avant l’exécution du code, et du coup on ne pousse pas en production un code défectueux (en tout cas pas au niveau des types de données manipulées).

Les types de données de base supportés par Typescript sont les suivants:

  • Boolean: Une simple valeur pouvant être vraie (true) ou fausse (false)
  • Number: Un nombre flottant (ex: 1.5)
  • String: Une chaîne de caractères (ex: « Hello World »)
  • Any: Un type désignant « n’importe quel type de données », équivalent du type object en javascript.
  • Void: Un type désignant du vide, rien, aucune valeur, souvent utilisé pour préciser qu’une fonction/méthode ne retourne pas de valeur (on attend du vide, donc rien)
  • Enum: Un type de données permettant de créer son propre type de données customisé avec un choix prédéfini dans les valeurs (ex: enum Color {Red, Green, Blue}).
  • Array: Un tableau pouvant contenir toutes sortes d’éléments (ex: [10,true, »google »] ). On peut également définir le type de données d’un tableau ( ex: let tab:Array; )
  • Null and Undefined: Equivalent des types null et undefined Javascript.

Pour plus de détails, rendez-vous sur la documentation en ligne du langage Typescript.

Les variables et les constantes

En Typescript, on n’emploie plus le mot clé var pour déclarer une variable mais les mot clefs let et const, introduits avec la norme ES6. Le mot clé const est utilisé, comme son nom l’indique, pour déclarer une valeur constante, çàd une valeur ne pouvant être modifiée, si vous essayez de modifier une constante, une erreur est levée. Le mot-clef let est, quant à lui utilisé pour déclarer une valeur variable, çàd une valeur capable de changer au cours de la durée de vie de votre programme.

Contrairement à Javascript, qui n’est pas typé, le Typescript l’est lui, comme son nom l’indique. Il est donc utile de préciser le type de données que l’on souhaite stocker au sein de la variable (ou de la constante) à l’aide de la syntaxe.

// constante, ne peut être modifiée
const LIGHT_SPEED:string = "299 792 458 m / s";
// variable, peut être modifiée
let msg:string = "Hello World"; 

Templates Strings

Les « templates strings » permettent d’insérer plus facilement des valeurs de variables au sein d’une chaîne de caractère, ces dernières peuvent également être définies sur plusieurs lignes. Il s’agit d’une nouveauté de la norme ES6, mais comme Typescript est un sur-ensemble de Javascript, elles sont supportées.

let jedi = {surname:"Obiwan", name:"Kenobi"}; 
let msg = `${jedi.name} ${jedi.surname} is the Jedi Master`;
console.log(msg);

Les fonctions

En Typescript comme en Javascript, les fonctions sont incontournables. Il s’agit de blocs d’instructions répétables que l’on peut appeler ( on dit invoquer ) autant de fois que nécessaire. Les fonctions Typescript, contrairement aux fonctions Javascript, précisent le type de données qu’elles renvoient, et si elles ne renvoient rien, alors le type de retour est void (du vide).

// les paramètres sont typés, et le type de la donnée 
// retournée également à l'aide de la syntaxe suivante:
function sum( a:number, b:number ):number{
    return a + b;
}

// quand une fonction ne retourne aucune donnée
// alors on le précise en utilsant le type "void"
function notif( msg:string ):void{
    alert(msg);
}

// les fonctions anonymes sont également utilisables, comme en JS
let anonymous:Function = function():void{
    console.log("I am an anonymous function");
};

// on peut invoquer une fonction anonyme comme en JS
anonymous();

Les fonctions fléchées

En Typescript comme en Javascript ES6, les fonctions fléchées sont supportées, bien entendu le typage des paramètres et de la donnée de retour est à ajouter au sein de la version Typescript. Il est également possible de spécifier des valeurs par défaut aux paramètres. Les fonctions fléchées ont également l’avantage de préserver le contexte dans lequel elles sont déclarées.

// fonction fléchée anonyme avec valeur de parmètre par défaut
let hello = (param_user: string = "user"): void => {
    console.log("Hello", param_user);
};

hello(); // invoquons cette fonction

// les fonctions fléchées anonymes préservent le contexte
class Gandalf {
    name: string = "Gandalf";
    introduce = () => {
        console.log("Hello my name is", this.name);
    }
}

// testons notre code
new Gandalf().introduce();

Les boucles

En Typescript, les boucles fonctionnent comme en Javascript:

let i:number = 10;

// une boucle for classique en Typescript
for( i = 0; i < 10; i ++){
    console.log(i);
}

// une boucle while classique en Typescript
i = 10;
while( --i > -1 ){
    console.log(i);
}

// une boucle do while classique en Typescript
i = -1;
do{
    if( i == -1 ){
        i = 10;
    }
}while( --i > -1)

Les tableaux

Typescript, comme Javascript, permet de travailler avec des tableaux de valeurs. A la différence qu’en Typescript, les tableaux (si on le souhaite) peuvent être typés ,ce qui signifie qu’ils ne peuvent contenir qu’un seul type de données. La déclaration de type pour les tableaux peut s’écrire de deux façons :

// première façon de déclarer un tableau typé
let notes:number[] = [
    0,10,12,7,8,20,13,15
];

// seconde façon de déclarer un tableau typé
let notes2:Array<number> = [
    0,10,12,7,8,20,13,15
];

Les enums

Typescript nous permet de créer et d’utiliser des enums. Les enums permettent au développeur de créer un lot de constantes et de les regrouper de façon à former un nouveau type de données.

// créons un type de données "Direction"
// qui peut prendre 4 valeurs différentes

enum Direction { Up = 1, Down = 2, Left = 3, Right = 4 };

let haut: Direction = Direction.Up;
let bas: Direction = Direction.Down;
let gauche: Direction = Direction.Left;
let droite: Direction = Direction.Right;

console.log(haut, bas, gauche, droite);

Modules

A partir de ECMAScript 2015 (ES6), Javascript introduit le concept de modules, et bien entendu, ce concept est supporté en Typescript. Les modules sont exécutés au sein de leur propre portée, et non pas au sein de la portée globale. Cela signifie que les variables, fonctions, classes, etc. Déclarées au sein d’un module ne sont pas visibles en dehors du module à moins qu’elles ne soient explicitement exportées à l’aide du mot-clé export. De fait, pour utiliser un élément exporté, au sein d’un module différent, il faut utiliser le mot-clé import.

export function toto(){
    console.log("toto est beau");
}
import {toto} from './ts_modules_1';
toto();

Programmation orientée objet (POO)

La programmation orientée objet est un style de programmation nous permettant de représenter des concepts informatiques sous forme d’objets. Pour conceptualiser un objet, nous avons besoin de plusieurs outils directement intégrés au langage. Il existe également plusieurs façons de « coder objet », Javascript est un langage orienté objet par prototypage, mais Typescript lui émule le comportement d’un langage orienté objet par classe. Il est important de retenir qu’un objet possède plusieurs caractéristiques:

  • Un objet possède des propriétés, çàd des variables qui lui appartiennent en propre, la portée de ces propriétés peut être, publique, protégée ou privée.
  • Un objet possède également des méthodes, çàd des fonctionnalités ( fonctions ) qui lui appartiennent en propre, la portée de ces méthodes peut être, publique, protégée ou privée.
  • Dans un langage orienté objet par classe, un objet peut hériter d’un autre objet.
  • Un objet peut prendre plusieurs formes et redéfinir ses propriétés héritées

Et il ne s’agit ici que des caractéristiques minimum, çàd celles qui définissent la base de la base d’un langage orienté objet, on parle des principes d’encapsulation, d’héritage et de polymorphisme.

Les classes

Voyons voir tout de suite comment coder une classe en Typescript.

class Hero{
    // une propriété peut être publique, protégée ou privée
    public name:string;
    public power:string;

    // la fonction constructrice est invoquée automatiquement 
    // à la création d'un nouvel objet 
    constructor( 
        param_name:string, 
        param_power:string
    ){
        // on attribue à nos propriétés les valeurs passées 
        // en paramètre
        this.name = param_name;
        this.power = param_power;
    }

    // une méthode peut être publique, protégée ou privée
    public sayMyName():void{
        console.log(this.name);
    }

    public sayMyPower():void{
        console.log(this.power);
    }
}

let myHero:Hero = new Hero("Batman", "Being rich");
myHero.sayMyName();

Héritage

Maintenant voyons voir comment une classe peut hériter d’une autre en Typescript.

class Personnage {
    // on veut transmettre cette propriété à nos enfants, on utilise donc protected
    protected name: string;
    // on veut transmettre cette propriété à nos enfants, on utilise donc protected
    protected lifepoint: number;

    constructor(param_name: string, param_lifepoint: number) {
        this.name = param_name;
        this.lifepoint = param_lifepoint;
    }

    //  on doit pouvoir demander à un personnage s'il est mort
    // sans être soi-même un personnage, la portée est donc publique
    public isDead(): boolean {
        // si le nombre de points de vie est inférieur 
        // ou égal à 0 alors le personnage est mort
        if (this.lifepoint <= 0) {
            return true;
        } 
        else {
            return false;
        }
    }

    public sayMyName():void{
        console.log(this.name);
    }
}
class Wizard extends Personnage{
    constructor( ){
        // on peut invoquer le constructor de la classe parente à l'aide de "super"
        super("Gandalf", 100);

        //... maintenant un nouvel objet de type wizard se nommera toujours 
        // Gandalf et aura 100 points de vie
    }

    // on réécrit la méthode sayMyName définie par le parent 
    // et héritée de celui-ci.
    public sayMyName():void{
        // mais on peut toujours invoquer l'ancienne "version" de la méthode
        // toujours à l'aide de "super"
        super.sayMyName();

        // si on veut, on peut ajouter des opérations supplémentaires
        console.log("I am a super magician !");
    }
}

// on crée un nouveau sorcier
let gandalf:Wizard = new Wizard();
// on crée un personnage Gollum qui possède 2 points de vie 
let gollum:Personnage = new Personnage("Gollum", 2);

gandalf.sayMyName();
gollum.sayMyName();

Conclusion

C’est tout pour ce petit tour de Typescript ! À partir de maintenant nous allons l’utiliser de façon rigoureuse, nous typerons donc l’ensemble de nos variables et nous allons également faire en sorte de créer des objets qui vont représenter les concepts que nous manipulerons. On se dit à bientôt, devant un petit café !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *