Développer en TypeScript

Introduction


Qu'est ce que TypeScript ?

TypeScript est un langage pour développer des applications conséquentes en JavaScript. Il permet d'ajouter des types optionnels, qui associés à des outils permet le développement d'applications JavaScript importantes, pour n'importe quelle navigateur, hote ou environnement d'exploitation. Le TypeScript est compilé en JavaScript.

>> Installation : npm i typescript --save-dev

Pourquoi utiliser TypeScript ? Il y a 2 raisons principales :
  • Le système de types introduit par TypeScript permet d'éviter les problèmes avec les types dynamiques qui sont fréquémment rencontrés avec JS
  • TypeScript implemente les dernières fonctionnalités ES Next (https://www.javascripttutorial.net/es-next/)

Qu'est que ts-node ?

ts-node est un moteur d'execution TypeScript et également un REPL for Node.js.

Un REPL (“REP-UL”) est une manière interactive d'interagir avec Node. L'acronyme REPL signifie :

  • "Read" : lecture de la commande utilisateur.
  • "Evaluate" : évaluation (execution) du code.
  • "Print" : affichage des résultats
  • "Loop" : reprendre à l'étape 1, pour une nouvelle instruction

ts-node va procéder à une transformation JIT ("Just in Time") du TypeScript en JavaScript et permettre ainsi l'éxecution sans précompilation. Ceci est fait en "s'accrochant" (via hook) au module de chargement des API de Node.

Pour créer un nouveau projet TypeScript
  • npm init -y  ; initialiser un projet
  • npm i typescript --save-dev : install le package TypeScript dans le projet
  • npx tsc --init : initialise le TypeScript

Types in TypeScript

TypeScript hérite des types natifs de JavaScript. Les types TypeScript sont de 2 catégories :

Les types primitifs :

Name Description
string     chaine de caractères
number     valeurs numériques
boolean     valeur vrai et faux
null             la valeur nulle 
undefined    la valeur "non définie". C'est la valeur par défaut pour toute variable non initialisée.
symbol     represente une valeur unique et constante

Les types objet
Les types objets sont les fonctions, les tableaux, les classes...

A quoi servent les types en TypeScript ?

Dans un premier temps, ils permettent au compilateur d'analyser le code et d'identifier d'éventuelles erreurs. Dans un second temps, le typage permet de mieux comprendre les valeurs associées aux variables.

Les Annotations TypeScript
TypeScript utilise des annotations pour spécifier explicitement les types des identifiants, tels que les variables, les fonctions, ou encore les objets...

TypeScript utilise la syntaxe ": type" après un identifiant, ou type doit etre un type valide. Une fois annoté, et donc typé, l'identifiant utilisé ne pourra pas être retypé, et son utilisation en tant que type différent entrainera une erreur du compilateur.

Exemples de syntaxe d'annotation :

let variableName: type;
let variableName: type = value;
const constantName: type = value;

Exemple d'annotations :

let nftName: string = 'Magic Owl';
let total: number = 25;
let active: boolean = true;

L'annotation d'un tableau utilise la syntaxe " : type[]"

let arrayName: type[];

Pour un tableau de string :

let names: string[] = ['John', 'Jane', 'Peter', 'David', 'Mary'];

Objets

La définition d'un type objet utilise la syntaxe pour annotation de type objet :

let nft: {
   name: string;
   id: number
};

Fonctions : Arguments et type retour
Exemple de déclaration en utilisant l'annotation des pramètres et l'annotation du type retour :

let greeting : (name: string) => string;

Cette déclaration désigne une fonction qui accepte un paramètre de type string et retourne un type string en valeur de retour :

greeting = function (name: string) {
    return `Hi ${name}`;
};

Adressage des problématiques de types dynamiques

Les paramètres des fonctions peuvent être typées, ce qui permet d'éviter les erreurs dans l'ordre des paramètres, puisque les erreurs de type seront detectées par l'IDE.

const showProduct = (name: string, price:number)  => {
  console.log(`The product ${name} costs ${price}$.`);
};

Une pratique consiste à déclarer une interface :

interface Nft{
    id: number,
    name: string,
    price: number
};

Ensuite ce type peut petre utilisé comme type de retour par exemple :

function getNft(id) : Nft{
  return {
    id: id,
    name: `Awesome Monkey ${id}`,
    price: 99.5
  }
}

En TypeScript, on peut définir un type comme une manière pratique de faire référence aux propriétés et métodes disponibles pour une valeur. 

Inférence de Types

  • L'inférence de type se produit lorsque l'on initialise une varibable, lorsque l'on assigne une valeur par défault à un paramètre, et lors de la détermination d'un type retour
  • TypeScript utilise l'algorithme du meilleur type commune pour selectionner le type candidat compatible avec toutes les variables.
  • TypeScript utilise également la frappe contextuelle pour inférer des types de variables en fonction de leur localisation.

Type Nombre

Tous les nombres en TypeScript sont soit des valeurs à virguel flottante (number) ou de grands entiers (bigint).

En TypeScript comme en JavaScript les types numériques supportés sont :

Décimale

let counter: number = 0;
let x: number = 100, 
    y: number = 200;

Binaire

La notation binaire utilise un zéro en tête suivi de la lettre b/B :

let bin = 0b100;
let anotherBin: number = 0B010;

Evidemment les chiffres suivant le b/B doivent être des 0 ou des 1.

Octale

La notation octale utiliuse la lettre o :

let octal: number = 0o10;

Evidemment les chiffres suivant le o doivent être compris entre 0 et 7.

Héxadécimale

La notation binaire utilise un zéro en tête suivi de la lettre x/X :

let hexadecimal: number = 0XA;

Evidemment les chiffres suivant le o doivent appartenir à l'ensemble 0123456789ABCDEF.

Attention, JavaScript propose le type Number (N majuscule) en référence au type non primif d'objet boxé/ L'utilisation de ce type est éviter.

Grand Entier

Les nombres dont la valeur est inférieure à 2^53-1. On appose un "n" à la suite du nombre :

let big: bigint = 9007199254740991n;

Type Chaine de Caractères

Commen JavaScript les guillemets simples ( ' ) ou doubles ( " ) sont utilisés pour délimiter les chaines de caractères. TypeScript supporte également le backtick ( ` ) pour travailler avec des chaines modèles, disposées sur plusieurs lignes ou faisant appel  l'interpolation de chaines.

let description = `This TypeScript string can 
span multiple 
lines
`;

String interpolations :

let firstName: string = `John`;
let title: string = `Web Developer`;
let profile: string = `I'm ${firstName}. 
I'm a ${title}`;

console.log(profile);

Type Booléen

let pending: boolean;
pending = true;
// after a while
// ..
pending = false;

Attention comme pour number et Number, on trouve boolean et Boolean (fait référence au type non primitif boxé).

Type Objet

Déclaration d'une variable de type object :

let employee: object;

employee = {
    firstName: 'John',
    lastName: 'Doe',
    age: 25,
    jobTitle: 'Web Developer'
};

console.log(employee);

Output:

{
  firstName: 'John',       
  lastName: 'Doe',
  age: 25,
  jobTitle: 'Web Developer'
}

Si l'on souhaite spécifier le type des propriétés de l'objet on peut 

Séparer la déclaration et l'initialisation :

let employee: {
    firstName: string;
    lastName: string;
    age: number;
    jobTitle: string;
};
Code language: CSS (css)
And then you assign the employee object to a literal object with the described properties:

employee = {
    firstName: 'John',
    lastName: 'Doe',
    age: 25,
    jobTitle: 'Web Developer'
};

Faire les 2 en même temps :

let employee: {
    firstName: string;
    lastName: string;
    age: number;
    jobTitle: string;
} = {
    firstName: 'John',
    lastName: 'Doe',
    age: 25,
    jobTitle: 'Web Developer'
};

object vs Object

En TypeScript , il existe également un type Object (O majuscule). 

object : type qui représente toutes les valeurs non primitives
Object: décrit les fonctionnalités de tous les objects (ex : toString(), valueOf()...)

Type Tableau

Le type tableu fait référence à une liste ordonnée de données. Pour déclarer un tableau typé, on utilise la syntaxe suivante :

let arrayName: type[];

Pour un tableau de chaines de caractères par exemple :

let skills: string[];

On peut ensuite lui ajouter des valeurs directement par assignation :

skills[0] = "Problem Solving";
skills[1] = "Programming";

ou en utilisant la méthode push()

skills.push('Software Design');

Déclaration d'un tableau de string à l'aide d l'inférence de type :

let skills = ['Problem Sovling','Software Design','Programming'];

Ce qui est équivalent à :

let skills: string[];
skills = ['Problem Sovling','Software Design','Programming'];

Propriétés et Méthodes du type Tableau

Lenght, forEach, map, reduce, filter

ex :

let series = [1, 2, 3];
let doubleIt = series.map(e => e* 2);
console.log(doubleIt);

Output:

[ 2, 4, 6 ] 

Déclarer un tableau multi-types :

let scores = ['Programming', 5, 'Software Design', 4]; 

TypeScript infère le tableau scores comme un tableau de type string | number :

let scores : (string | number)[];

scores = ['Programming', 5, 'Software Design', 4]; 

Les Tuples

Un Tuple se comporte comme un tableau excepté que :
  • le nombre d'élements du tuple est fixe
  • le type des élements est connu
let skill: [string, number];
skill = ['Programming', 5];

Depuis TypeScript 3.0, un tuple peut avoir des élements optionneles en utilisant (?) :


let bgColor, headerColor: [number, number, number, number?];
bgColor = [0, 255, 255, 0.5];
headerColor = [0, 255, 255];

Type Enum

The following example creates an enum that represents the months of the year:

enum Month {
    Jan = 1, // 1 au lieu de 0
    Feb, // donc 2 au lieu de 1
    Mar,
    Apr,
    May,
    Jun,
    Jul,
    Aug,
    Sep,
    Oct,
    Nov,
    Dec
};

On peut utiliser cet enum ainsi :

function isItSummer(month: Month) {
    let isSummer: boolean;
    switch (month) {
        case Month.Jun:
        case Month.Jul:
        case Month.Aug:
            isSummer = true;
            break;
        default:
            isSummer = false;
            break;
    }
    return isSummer;
}

Type any

Pour manipuler une valeur dont on ne connait pas le type à la compilation, on peut utiliser le type any. Ainsi si on déclare une variable sans la typer, TypeScript assume l'utilisation du type any :

// json may come from a third-party API
const json = `{"latitude": 10.11, "longitude":12.12}`;

// parse JSON to find location
const currentLocation = JSON.parse(json);
console.log(currentLocation);
Code language: JavaScript (javascript)
Output:

{ latitude: 10.11, longitude: 12.12 }

Le type any permet de migrer gentiment vers le typage statique.

Type void

Le type void est utilisé pour spécifier l'absence complète de type, comme un méthode qui ne retourne rien.

Type never

Ne contient aucune valeur
Est utilisé pour les méthodes qui provoquent une erreur ou ne retourne jamais (boucle infinie par ex).

Type union

Ce type permet de combiner plusieurs types en un seul. Par exemple la variable suivante peut etre un nombre ou une chaine de caractères :

let result: number | string;
result = 10; // OK
result = 'Hi'; // also OK
result = false; // a boolean value, not OK

Utilisation pour les paramètres d'une mthode :

function add(a: number | string, b: number | string) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a + b;
    }
    if (typeof a === 'string' && typeof b === 'string') {
        return a.concat(b);
    }
    throw new Error('Parameters must be numbers or strings');
}

Type alias

Ce type permet de déclarer un nouveau nom pour un type :
type chars = string;
let messsage: chars; // same as string type

C'est particulièrement utile dans le cadre du type union :

type alphanumeric = string | number;
let input: alphanumeric;
input = 100; // valid
input = 'Hi'; // valid
input = false; // Compiler error

Type Chaine de Caractères littérale

Le type "string literal" permet de limiter les valeurs que peut prendre une chaine de caractères :

let click: 'click';
click = 'click'; // valid
click = 'dblclick'; // compiler error

Ce type est pratique notamment lorsqu'il est utilisé avec le type union et le type alias :

type MouseEvent: 'click' | 'dblclick' | 'mouseup' | 'mousedown';
let mouseEvent: MouseEvent;
mouseEvent = 'click'; // valid
mouseEvent = 'dblclick'; // valid
mouseEvent = 'mouseup'; // valid
mouseEvent = 'mousedown'; // valid
mouseEvent = 'mouseover'; // compiler error

Instructions conditionnelles

if(condition) {
   // if-statement
}

if(condition) {
   // if-statements
} else {
  // else statements;
}

const max = 100;
let counter = 100;

counter < max ? counter++ : counter = 1;

console.log(counter);


let discount: number;
let itemCount = 11;

if (itemCount > 0 && itemCount <= 5) {
    discount = 5;  // 5% discount
} else if (itemCount > 5 && itemCount <= 10) {
    discount = 10; // 10% discount 
} else {
    discount = 15; // 15%
}

switch ( expression ) {
   case value1:
       // statement 1
       break;
   case value2:
       // statement 2
       break;
   case valueN:
       // statement N
       break;
   default: 
       // 
       break;
}

for(initialization; condition; expression) {
    // statement
}

Bloc optionnels :

let i = 0;
for (; i < 10; i++) {
    console.log(i);
}

Like the initialization block, you can omit the condition block.

However, you must escape the loop when a condition is met by using the if and break statements. Otherwise, you will create an infinite loop that causes the program to executes repeatedly until it is crashed.

for (let i = 0; ; i++) {
    console.log(i);
    if (i > 9) break;
}

The following example illustrates a for loop that omits all three blocks:

let i = 0;
for (; ;) {
    console.log(i);
    i++;
    if (i > 9) break;
}

Boucle while

let counter = 0;

while (counter < 5) {
    console.log(counter);
    counter++;
}

Boucle do...while

do {
    // do something
} while(condition);

Les boucles ou switch peuvent être interrompues avace l'instruction "break". L'itération courante peut également être "ignorée" avec l'instruction "continue".

Exemple :

let index = -1;

while (index < 9) {

    index = index + 1;

    if (index % 2)
        continue;

    console.log(index);
}

Output:

0
2
4
6
8   


Ressources :
  • https://www.typescripttutorial.net/
  • https://www.javascripttutorial.net/es-next/

Commentaires

Posts les plus consultés de ce blog

Sécurité des Applications

Principes de la Programmation Orientée Objet

Principe de Responsabilité Unique