đ TypeScript â Le Superset JavaScript TypĂ©
Guide complet IDEOâLab : Installation (tsc), Types, Interfaces, Generics & tsconfig.json.
Vue d'ensemble
JavaScript + Typage Statique. "Superset" de JS.
JavaScript Typage StatiquePourquoi TypeScript ?
Ăviter les erreurs "runtime", autocomplĂ©tion, scalabilitĂ©.
Sécurité AutocomplétionInstallation (tsc)
npm install -g typescript, tsc (Compilateur).
Fichier tsconfig.json
target (ES6), module, strict (True !).
Types Primitifs & Inférence
string, number, boolean, Inférence de type.
Types : Arrays & Tuples
string[], Array<number>, [string, number].
any vs unknown vs void
any (Désactivé), unknown (Sûr), void (Pas de retour).
Typage des Fonctions
(param: string): number, ParamĂštres optionnels (?).
Union & Literal Types
string | number, type Status = "pending" | "done".
Interfaces (Objets)
interface User {}, readonly, ? (optionnel).
interface vs type
extends (Interface) vs & (Type). Débat et usages.
Classes (OOP)
public, private, protected, implements.
Generics (Génériques)
function<T>(arg: T): T, Array<T>.
Utility Types (Types Utilitaires)
Partial<T>, Readonly<T>, Pick<T, K>, Omit<T, K>.
Exécuter (Node.js)
ts-node (Dev), tsc && node dist/ (Prod).
Cas d'usage : React (.tsx)
React.FC, useState<T>, Props interface.
Cheat-sheet (Types)
Syntaxe des types de base et complexes.
cheat TypesQu'est-ce que TypeScript ?
TypeScript (TS) est un **superset (sur-ensemble) open-source de JavaScript**, développé par Microsoft.
"Superset" signifie que **tout code JavaScript valide est déjà du code TypeScript valide**. TS ajoute une seule chose : un **systÚme de typage statique optionnel**.
La Transpilation (TS -> JS)
Les navigateurs (Chrome, Firefox) et Node.js ne comprennent *pas* TypeScript. Ils ne comprennent que JavaScript.
Votre code .ts doit ĂȘtre **transpilĂ©** (compilĂ©) par le compilateur TypeScript (tsc) en code JavaScript .js standard (ex: ES6) pour pouvoir ĂȘtre exĂ©cutĂ©.
Flux de travail
+---------------------+
| main.ts (Votre code) |
| (Avec Types) |
+---------------------+
|
| (1. Lancer 'tsc')
âŒ
+---------------------+
| tsc (Compilateur) |
| (Vérifie les erreurs) |
+---------------------+
|
| (2. GénÚre)
âŒ
+-----------------------+
| main.js (Code compilé) |
| (JavaScript pur) |
+-----------------------+
|
| (3. Exécuté par)
âŒ
[Navigateur ou Node.js]
Le ProblĂšme (JavaScript "dynamique")
Le typage dynamique de JS est source d'erreurs silencieuses, découvertes uniquement à l'exécution (runtime).
// code.js
function calculerTotal(panier) {
let total = 0;
// (Le dev pense que 'panier' est un array d'objets)
panier.forEach(item => {
total += item.prix;
});
return total;
}
// (6 mois plus tard, un autre dev...)
// (Passe un objet, pas un array)
const panier_bug = { id: 1, prix: 50 };
calculerTotal(panier_bug);
// RĂSULTAT:
// TypeError: panier.forEach is not a function
// (Erreur découverte en production, par un client)La Solution (Typage Statique)
TypeScript (et votre IDE, ex: VS Code) dĂ©tecte l'erreur **avant** l'exĂ©cution, pendant la compilation (ou mĂȘme l'Ă©criture).
// code.ts
interface Item {
prix: number;
}
function calculerTotal(panier: Item[]) { // (Type: Array de Item)
let total = 0;
panier.forEach(item => {
total += item.prix;
});
return total;
}
const panier_bug = { id: 1, prix: 50 };
calculerTotal(panier_bug);
// ^
// RĂSULTAT (Ă la compilation):
// Argument of type '{ id: number; prix: number; }'
// is not assignable to parameter of type 'Item[]'.tsc)1. Installation (via npm)
TypeScript est un outil Node.js. (Nécessite Node.js/npm).
# 1. (Option A) Globalement npm install -g typescript # 2. (Option B) Par projet (Recommandé) npm install typescript --save-dev
2. tsc (Le Compilateur)
tsc (TypeScript Compiler) est la commande CLI.
# (Si global) tsc main.ts # (Crée main.js) # (Si local) npx tsc main.ts
3. ts-node (Dev)
ts-node est un outil (de dev) qui compile et exécute le .ts en une seule étape (sans créer de .js).
npm install -g ts-node # (Exécute main.ts directement) ts-node main.ts
tsconfig.json (Le Cerveau)Initialisation (--init)
tsconfig.json (Ă la racine) dit Ă tsc *comment* compiler le projet.
# GénÚre un 'tsconfig.json' par défaut (trÚs commenté) tsc --init
Si tsc est lancé sans argument, il cherche tsconfig.json et compile tout le projet.
compilerOptions (Les plus importantes)
{
"compilerOptions": {
/* Cible (Quel JS générer ?) */
"target": "ES2016", // (ES6) (ou 'ESNext')
/* Modules (Comment gérer 'import'/'export') */
"module": "NodeNext", // (Moderne pour Node.js)
// "module": "ESNext" (Pour le Web/Vite)
/* Racine (OĂč est le TS ? OĂč va le JS ?) */
"rootDir": "./src",
"outDir": "./dist",
/* ----- LE PLUS IMPORTANT ----- */
/* Strict (Active toutes les vérifications) */
"strict": true,
// (Inclut: noImplicitAny, strictNullChecks, etc.)
/* Interopérabilité */
"esModuleInterop": true,
"skipLibCheck": true
},
/* Fichiers Ă inclure/exclure */
"include": ["src/**/*"],
"exclude": ["node_modules"]
}Annotation (Explicite)
Vous "annotez" la variable avec : type.
// Primitifs let nom: string = "Alice"; let age: number = 30; let estAdmin: boolean = true; let n: null = null; let u: undefined = undefined;
Inférence (Implicite)
TS est intelligent. Si vous assignez une valeur Ă l'initialisation, il "devine" (infĂšre) le type.
let nom = "Alice"; // (TS infÚre 'string') let age = 30; // (TS infÚre 'number') // Erreur (détectée) nom = 123; // Type 'number' is not assignable to type 'string'.
Arrays
Il y a deux syntaxes pour les tableaux.
// Syntaxe 1 (Recommandée) let noms: string[] = ["Alice", "Bob"]; let ages: number[] = [10, 20, 30]; // Syntaxe 2 (Générique) let noms_alt: Array= ["Alice", "Bob"]; // Erreur noms.push(123); // Argument of type 'number'...
Tuples
Un "Tuple" est un tableau avec une **longueur fixe** et des **types fixes** (dans l'ordre).
let user: [string, number]; // OK user = ["Alice", 30]; // Erreur (ordre) user = [30, "Alice"]; // Erreur (longueur) user = ["Alice", 30, true];
any vs unknown vs void| Type | Description | Usage |
|---|---|---|
any | "DĂ©sactive le typage". Accepte n'importe quoi, permet n'importe quel appel. Ă ĂVITER. | Migration rapide de vieux code JS. |
unknown | "Le any sécurisé". Accepte n'importe quoi, mais vous **oblige** à vérifier le type (if (typeof...)) avant de l'utiliser. | Données externes (API JSON, try/catch). |
void | La fonction ne retourne aucune valeur (return;). | Fonctions (ex: console.log). |
never | La fonction ne retourne jamais (ex: throw new Error() ou boucle infinie). | Type avancé. |
let data: unknown = JSON.parse(api_response);
if (typeof data === "string") {
console.log(data.toUpperCase()); // OK
}
if (typeof data === "number") {
console.log(data.toFixed(2)); // OK
}ParamĂštres & Retour
// (param1: type, param2: type): type_retour
function addition(a: number, b: number): number {
return a + b;
}
// (TS infĂšre 'number' comme retour, mais c'est une
// bonne pratique de l'expliciter)
// Fonction fléchée (Arrow)
const soustraction = (a: number, b: number): number => {
return a - b;
};
// Type 'void' (pas de retour)
function logMessage(message: string): void {
console.log(message);
}ParamÚtres Optionnels (?) & Défaut
// 'prenom' est optionnel
function saluer(nom: string, prenom?: string): string {
if (prenom) {
return `Bonjour, ${prenom} ${nom}`;
}
return `Bonjour, ${nom}`;
}
// ParamÚtre par défaut
function saluerDefaut(nom: string, prenom: string = "M."): string {
return `Bonjour, ${prenom} ${nom}`;
}|) & Alias (type)Types Union (|)
Permet Ă une variable d'avoir plusieurs types.
let id: string | number;
id = 101; // OK
id = "abc-101"; // OK
// (Utile pour les "narrowing" (rétrécissement))
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // (TS sait que c'est un string)
} else {
console.log(id); // (TS sait que c'est un number)
}
}Alias (type)
Permet de nommer un type (pour le réutiliser).
Types "Literal"
Le type est la valeur elle-mĂȘme (ex: "pending").
// 1. Définir un type "Status"
type Status = "pending" | "processing" | "done" | "failed";
// 2. Définir un ID
type UserID = string | number;
// 3. Utiliser les alias
function updateStatus(id: UserID, status: Status): void {
// ...
}
updateStatus(123, "done"); // OK
updateStatus("abc", "pending"); // OK
updateStatus(123, "error"); // Erreur !Interface (Définir la "Forme" d'un objet)
interface est la façon la plus courante de définir la structure d'un objet. (type peut aussi le faire, mais interface est plus flexible pour l'OOP).
// 1. Définition de l'interface
interface Utilisateur {
readonly id: number; // Lecture seule
nom: string;
email: string;
age?: number; // '?' = Optionnel
}
// 2. Utilisation (typage de variable)
const user: Utilisateur = {
id: 1,
nom: "Alice",
email: "alice@mail.com"
// (Erreur si 'nom' manque)
// (Erreur si 'id' est modifié)
};
// 3. Utilisation (typage de fonction)
function printUser(user: Utilisateur): void {
console.log(user.nom);
}Interface (Héritage & Implémentation)
interface Personne {
nom: string;
}
// 1. Héritage (Admin "étend" Personne)
interface Admin extends Personne {
role: "admin" | "superadmin";
}
// 2. Interface de Fonction
interface MathFunc {
(a: number, b: number): number;
}
const add: MathFunc = (a, b) => a + b;
// 3. (Voir 3.3) Implémentation (Classe)
class Employe implements Personne {
nom: string;
constructor(n: string) { this.nom = n; }
}interface vs typeLes deux peuvent décrire des objets, mais avec des nuances :
| CritĂšre | interface (Interface) | type (Alias de Type) |
|---|---|---|
| Usage | Objets, Classes (OOP). | Tout (Objets, Unions |, Primitifs). |
| Héritage | interface A extends B {} | type C = A & B; (Intersection &). |
| Fusion (Merging) | Oui (deux interface A fusionnent). | Non (déclaration unique). |
Conclusion (Bonne pratique) :
1. Utilisez interface par défaut pour définir des "formes" (Objets, Props React).
2. Utilisez type pour définir des Unions (string | number) ou des types "Literal" ("pending" | "done").
TS ajoute les modificateurs de visibilité (public, private, protected) et readonly aux classes JS.
import { Personne } from './interfaces';
class Employe implements Personne {
// 1. Raccourci "Parameter Properties"
// (Déclare ET assigne 'nom', 'salaire', 'departement')
constructor(
public nom: string,
private salaire: number,
protected departement: string
) {}
public getSalaire(): number {
// (AccĂšs 'private' OK)
return this.salaire;
}
}
class Manager extends Employe {
public getDepartement(): string {
// (AccĂšs 'protected' OK)
return this.departement;
}
}
const emp = new Employe("Bob", 50000, "IT");
console.log(emp.nom); // OK
// console.log(emp.salaire); // Erreur: 'salaire' is private<T>Les "Generics" (Génériques) permettent d'écrire des fonctions ou des classes qui fonctionnent avec n'importe quel type (T), tout en **conservant** ce type (contrairement à any).
ProblĂšme (sans Generics)
function identity(arg: any): any {
return arg;
}
let output = identity("hello");
// 'output' est 'any' (on a perdu le type 'string')Solution (avec Generics <T>)
// T = Variable de Type function identity(arg: T): T { return arg; } // 1. Explicite let output_s = identity ("hello"); // 'output_s' est 'string' // 2. Implicite (TS infĂšre T) let output_n = identity(123); // 'output_n' est 'number' // Exemple (API Response) interface ApiResponse { data: T; status: number; } // type ReponseUser = ApiResponse // type ReponseArticle = ApiResponse
TS fournit des "fonctions de type" (mappées) pour transformer des interfaces existantes.
interface User {
id: number;
nom: string;
email: string;
}
// 1. Partial: Rend tous les champs optionnels
// (Pour un UPDATE)
type UserUpdate = Partial;
// { id?: number; nom?: string; email?: string; }
// 2. Pick: Ne garde que certains champs
type UserLogin = Pick;
// { email: string; nom: string; }
// 3. Omit: Exclut certains champs
// (Pour un CREATE)
type UserCreate = Omit;
// { nom: string; email: string; }
// 4. Readonly: Rend tous les champs 'readonly'
type ReadonlyUser = Readonly;
// 5. Record: Crée un objet (Map)
type UserMap = Record;
// const users: UserMap = { "user-1": { id: 1, ... } } Dev (ts-node + nodemon)
ts-node (Transpile + Exécute) + nodemon (Observe les changements).
npm install -D typescript ts-node nodemon @types/node
# (package.json)
"scripts": {
"dev": "nodemon src/server.ts"
}Production (tsc + node)
En production, on compile d'abord en JS (rapide), puis on exécute le JS (natif).
# 1. (package.json)
"scripts": {
"build": "tsc",
"start": "node dist/server.js"
}
# 2. (Déploiement)
npm install
npm run build
npm run start.tsx)# (Créer un projet Vite + TS + React) npm create vite@latest mon-app -- --template react-ts # (Fichier .tsx = TS + JSX)
// components/Bouton.tsx
import React, { useState } from 'react';
// 1. Définir les "Props" (entrées)
interface BoutonProps {
texte: string;
disabled?: boolean;
}
// 2. Typer le composant
// (React.FC = Function Component)
const Bouton: React.FC = ({ texte, disabled = false }) => {
// 3. Typer le "State"
const [count, setCount] = useState(0);
return (
);
};
export default Bouton; Types de base
let nom: string = "a"; let age: number = 1; let ok: boolean = true; let data: any = "..."; let data2: unknown = "..."; let vide: void = undefined; let n: null = null;
Types (Union & Alias)
type Status = "pending" | "done"; type UserID = string | number;
Types (Array & Objet)
// Array let liste: string[] = ["a", "b"]; let liste2: Array= [1, 2]; // Tuple let tuple: [string, number] = ["a", 1]; // Objet (Interface) interface User { id: number; nom: string; optionnel?: boolean; } const user: User = { id: 1, nom: "A" }; // Fonctions const maFn = (nom: string): number => { return 1; }
