Introduction à TypeScript¶
TypeScript c’est du JavaScript avec des types!
Pourquoi utiliser TypeScript? Ça aide à trouver les erreurs dans notre code.
Manuel
Installation de TypeScript¶
Pour installer TypeScript, utiliser la commande suivante :
Note
Ça installe sur votre poste le compilateur TypeScript qui transforme le code en JavaScript. Nous allons voir npm plus en détail au prochain cours
Indiquer les types aux variables¶
Dans votre éditeur de code, TypeScript dit que la variable prénom est un string et vous informe que vous l’utilisez avec un autre type. C’est la base de TypeScript, vous éviter des erreurs de la sorte.
Types primitifs¶
TypeScript a les types primitifs suivants :
- string
- number
- boolean
- null
- void
- any
- never
- unknown
Inférence¶
TypeScript peut deviner le type selon le contexte :
L'inférence ne marche pas toujours¶
Des fois, l’inférence ne fonctionne pas :
Dans ce cas, il faut être explicite :
Any¶
Le type Any est pour indiquer que vous prévoyez mettre plus d’un type dans la même variable.
{C’est à proscrire}
let quelqueChose : any = 'Une patate';
quelqueChose = 12;
quelqueChose = true;
quelqueChose = { nom: 'Taleb', prenom: 'Frédérick' };
Ça empêche TypeScript de vous aider!
Never¶
Utilisé comme paramètre de retour d’une fonction qui ne se terminera jamais.
function bloucleSansFin(): never {
while (true) {
console.log("À l'aide, je suis pris ici!");
}
}
Void¶
Utiliser void lorsque votre fonction ne retourne pas de valeur :
Unknown¶
Unknown est comme Any, dans le sens qu’il peut recevoir n’importe quel type.
Mais unknown ne peut etre assigné à aucun autre type de variable que unknown et any:
Objets¶
Les objets peuvent être typés comme les variables :
Types¶
Si nous voulons créer plusieurs objets avec la même forme, créer un type peut aider :
/**
* Représente un chat
* @property {string} nom - Le nom du chat
* @property {number} nombreDeVies - Le nombre de vies restantes au chat
* @property {string[]} surnoms - Tableau de tous les surnoms du chat
* @property {string=} race - Race du chat
*/
type Chat = {
nom: string;
nombreDeVies: number;
surnoms: string[];
race?: string;
};
/**
* Affiche le détail d'un chat
*
* @param {Chat} unchat - Un chat à afficher
**/
function afficherChat(unchat: Chat): void {
console.log(
`Le chat se nomme ${unchat.nom} et a ${unchat.nombreDeVies} vies.`
);
}
const fanta: Chat = {
nom: 'Fanta',
nombreDeVies: 9,
surnoms: ['Chaton', 'Tannant'],
};
const guizmo: Chat = {
nom: 'Guizmo',
nombreDeVies: 3,
surnoms: ['Mou'],
race: 'Siamois',
};
afficherChat(fanta);
afficherChat(guizmo);
On s’assure que tous les objets ont les mêmes attributs.
On valide que seulement les objets d’un type peuvent être utilisés dans une fonction.
Paramètres de fonctions¶
Très utile pour documenter une fonction :
/**
* Multiplie deux nombres
*
* @param {number} nombre1 - Premier nombre
* @param {number} nombre2 - Second nombre
**/
function multiplierDeuxNombres(nombre1: number, nombre2: number): number {
return nombre1 * nombre2;
}
const produit1 = multiplierDeuxNombres(2, 4);
const produit2 = multiplierDeuxNombres('DIX', 'DEUX'); // Donne une erreur
Compiler TypeScript en JavaScript¶
TypeScript ne peut pas être exécuté directement par Node ou par le navigateur. Il faut le compiler (parfois appelé « transpiler ») en JavaScript avant son exécution.
Configurer tsc¶
Pour compiler, il est important de générer le fichier tsconfig.json avant de faire la commmande tsc :
Voici les résultats, selon la version de JavaScript :
TypeScript¶
/**
* Représente un chat
* @property {string} nom - Le nom du chat
* @property {number} nombreDeVies - Le nombre de vies restantes au chat
* @property {string[]} surnoms - Tableau de tous les surnoms du chat
* @property {string=} race - Race du chat
*/
type Chat = {
nom: string;
nombreDeVies: number;
surnoms: string[];
race?: string;
};
/**
* Affiche le détail d'un chat
*
* @param {Chat} unchat - Un chat à afficher
**/
function afficherChat(unchat: Chat): void {
console.log(
`Le chat se nomme ${unchat.nom} et a ${unchat.nombreDeVies} vies.`
);
}
const fanta: Chat = {
nom: 'Fanta',
nombreDeVies: 9,
surnoms: ['Chaton', 'Tannant'],
};
const guizmo: Chat = {
nom: 'Guizmo',
nombreDeVies: 3,
surnoms: ['Mou'],
race: 'Siamois',
};
afficherChat(fanta);
afficherChat(guizmo);
JavaScript ES6¶
/**
* Affiche le détail d'un chat
*
* @param {Chat} unchat - Un chat à afficher
**/
function afficherChat(unchat) {
console.log("Le chat se nomme ".concat(unchat.nom, " et a ").concat(unchat.nombreDeVies, " vies."));
}
var fanta = {
nom: 'Fanta',
nombreDeVies: 9,
surnoms: ['Chaton', 'Tannant'],
};
var guizmo = {
nom: 'Guizmo',
nombreDeVies: 3,
surnoms: ['Mou'],
race: 'Siamois',
};
afficherChat(fanta);
afficherChat(guizmo);
JavaScript ES2022¶
'use strict';
/**
* Affiche le détail d'un chat
*
* @param {Chat} unchat - Un chat à afficher
**/
function afficherChat(unchat) {
console.log(
`Le chat se nomme ${unchat.nom} et a ${unchat.nombreDeVies} vies.`
);
}
const fanta = {
nom: 'Fanta',
nombreDeVies: 9,
surnoms: ['Chaton', 'Tannant'],
};
const guizmo = {
nom: 'Guizmo',
nombreDeVies: 3,
surnoms: ['Mou'],
race: 'Siamois',
};
afficherChat(fanta);
afficherChat(guizmo);
Configuration de tsc – tsconfig.json¶
tsconfig.json permet de configurer comment tsc compile les fichiers TypeScript.
Quelques paramètres utiles :
{
"compilerOptions": {
"target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "commonjs" /* Specify what module code is generated. */,
"outDir": "./dist", /* Specify an output folder for all emitted files. */
"strict": true /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
Union de types¶
L’union de type permet d’indiquer à TypeScript que nous acceptons deux types de données pour une variable ou un argument de fonction. Par exemple :
function devineMonAge(age: number | string) {
console.log(`Ton age est ${age}`);
}
devineMonAge(40);
devineMonAge('Trente huit');
Manuel
Égalité : == vs ===¶
JavaScript (et TypeScript) offre deux opérateurs de comparaison d’égalité :
| Opérateur | Nom | Comportement |
|---|---|---|
== |
Égalité abstraite | Compare les valeurs après conversion de type |
=== |
Égalité stricte | Compare les valeurs et le type sans conversion |
console.log(1 == "1"); // true ← JavaScript convertit "1" en number
console.log(1 === "1"); // false ← types différents (number vs string)
console.log(0 == false); // true ← false est converti en 0
console.log(0 === false);// false ← types différents (number vs boolean)
console.log(null == undefined); // true ← cas spécial de ==
console.log(null === undefined); // false ← types différents
Toujours utiliser === en TypeScript
L’opérateur == peut produire des résultats surprenants à cause des conversions implicites. En TypeScript, utilisez toujours === (et !== pour l’inégalité). TypeScript avec la règle ESLint eqeqeq vous avertira si vous utilisez ==.
Manuel
Comparaison de tableaux et références en mémoire¶
Pour les tableaux (et les objets), === ne compare pas les entrées — il compare la référence en mémoire. Deux tableaux avec les mêmes valeurs ne sont pas égaux s'ils sont deux objets distincts en mémoire.
const a = [1, 2, 3];
const b = [1, 2, 3];
console.log(a === b); // false ← deux tableaux distincts en mémoire
console.log(a == b); // false ← même résultat, même pour ==
De même, copier un tableau avec = ne crée pas une copie : les deux variables pointent vers le même tableau en mémoire. Modifier l'un modifie l'autre.
const original = [1, 2, 3];
const copie = original; // ← copie la référence, pas les données!
copie.push(4);
console.log(original); // [1, 2, 3, 4] ← original est aussi modifié!
console.log(copie); // [1, 2, 3, 4]
console.log(original === copie); // true ← même référence en mémoire
graph LR
original --> T["[1, 2, 3, 4]"]
copie --> T
Pour créer une vraie copie indépendante, il faut utiliser le spread ... ou Array.from() :
const original = [1, 2, 3];
const vraiecopie = [...original]; // ← nouveau tableau en mémoire
vraiecopie.push(4);
console.log(original); // [1, 2, 3] ← inchangé
console.log(vraiecopie);// [1, 2, 3, 4]
console.log(original === vraiecopie); // false ← références différentes
Même comportement pour les objets
Les objets fonctionnent exactement de la même façon. const b = a copie la référence. Pour copier un objet, utilisez { ...a } ou structuredClone(a) pour une copie profonde.
Rétrécir le type¶
Quand nous acceptons plus d’un type pour un argument, il est parfois nécessaire de bien déterminer le type dans le corps de la fonction :
Par exemple :
function doubler(item: number | string) {
if (typeof item === 'string') {
return `${item} - ${item}`;
}
return item * 2;
}
console.log(doubler('Allo'));
console.log(doubler(12));
Union de type pour créer un alias¶
type Utilisateur = {
nom: string;
age: number;
actif: boolean;
};
type Administrateur = {
nom: string;
niveau: number;
};
type Employe = Utilisateur | Administrateur;
Rétrécir le type – autre exemple¶
const roy: Administrateur = {
nom: 'Roy',
niveau: 99,
};
const richmond: Utilisateur = {
nom: 'Richmond',
age: 40,
actif: true,
};
/**
* Dire bonjour à un employé
*
* @param {Employe} employe - L'employé à qui on dit bonjour
*
*/
function direBonjour(employe: Employe) {
if ('niveau' in employe) {
console.log(
`Bonjour Adminisatrateur ${employe.nom} de niveau ${employe.niveau}`
);
return;
}
console.log(`Bonjour Utilisateur ${employe.nom} agé de ${employe.age} ans`);
}
direBonjour(roy);
direBonjour(richmond);
Union de type – pour restreindre les valeurs¶
type Chat {
nom: string,
age: number,
race: 'Ragdoll' | 'Siamois' | 'Sphynx',
};
const fanta : Chat = {
nom: 'Fanta',
age: 8,
race: 'Ragdoll',
};
/*
* La race pour Furguie n'est pas acceptée pour le type Chat
*/
const furguie : Chat = {
nom: 'Furguie',
age: 3,
race: 'colorpoint',
};
Enum¶
Un enum nous permet de définir un ensemble de constantes nommées.
enum Race {
Ragdoll,
Siamois,
Sphynx,
}
type Chat = {
nom: string;
age: number;
race: Race;
};
const fanta: Chat = {
nom: 'Fanta',
age: 8,
race: Race.Ragdoll,
};
Manuel
Interface¶
Une interface est une façon différente en TypeScript pour décrire la forme d’un objet :
enum Race {
Ragdoll,
Siamois,
Sphynx,
}
interface Chat {
nom: string;
age: number;
race: Race;
};
const fanta: Chat = {
nom: 'Fanta',
age: 8,
race: Race.Ragdoll,
};
Generics¶
Comme dans C#, TypeScript support les generics :
Manuel