TypeScript pour débutants : le guide complet 2025 pour passer de JavaScript à TypeScript
Apprenez TypeScript de zéro : types, interfaces, classes, génériques. Passez de JavaScript à TypeScript avec ce tutoriel complet et pratique.
Introduction : pourquoi TypeScript change tout
Tu codes en JavaScript et tu en as marre des bugs qui apparaissent en production ? Des undefined is not a function qui te font perdre des heures ? TypeScript est la solution. C'est JavaScript avec un super-pouvoir : le typage statique qui attrape tes erreurs avant l'exécution.
TypeScript, c'est JavaScript + des types. Tout code JavaScript valide est du TypeScript valide. Mais TypeScript te donne des outils pour écrire du code plus robuste, plus maintenable, et avec une meilleure autocomplétion dans ton IDE.
Fun fact : TypeScript est développé par Microsoft et est utilisé par Angular, Vue 3, React (via create-react-app), Node.js, Deno, et des milliers de projets open-source. En 2025, c'est devenu le standard de facto pour les projets JavaScript professionnels.
Qu'est-ce que TypeScript exactement ?
TypeScript est un superset de JavaScript, c'est-à-dire qu'il ajoute des fonctionnalités à JavaScript sans rien enlever.
- 📝 Types statiques : tu déclares le type de tes variables (string, number, boolean, etc.)
- 🛡️ Sécurité au compile-time : les erreurs sont détectées avant l'exécution
- 🔍 Autocomplétion puissante : ton IDE connaît tous les types et te suggère les bonnes méthodes
- 📚 Documentation intégrée : les types servent de documentation vivante
- ⚙️ Compilation vers JavaScript : TypeScript se compile en JavaScript standard (ES3 à ESNext)
TypeScript vs JavaScript : comparaison directe
JavaScript classique :
function calculerTotal(prix, quantite) {
return prix * quantite;
}
calculerTotal(10, "5"); // ❌ Retourne "1010105" au lieu de 50 !
calculerTotal(); // ❌ NaN
calculerTotal(10, 5, 20); // ✅ Fonctionne mais ignore le 3e param
TypeScript :
function calculerTotal(prix: number, quantite: number): number {
return prix * quantite;
}
calculerTotal(10, "5"); // ❌ Erreur de compilation !
calculerTotal(); // ❌ Erreur de compilation !
calculerTotal(10, 5, 20); // ❌ Erreur de compilation !
calculerTotal(10, 5); // ✅ Retourne 50
Avec TypeScript, toutes ces erreurs sont détectées avant même de lancer ton code. Plus besoin de chercher pourquoi ton calcul retourne "1010105" en production !
Installation et setup de TypeScript
Prérequis
- Node.js installé (version 16+)
- Un éditeur de code (VS Code recommandé)
- Des bases en JavaScript (variables, fonctions, objets)
Installation
# Installation globale
npm install -g typescript
# Vérifier l'installation
tsc --version
# Créer un projet TypeScript
mkdir mon-projet-ts
cd mon-projet-ts
npm init -y
npm install --save-dev typescript
# Initialiser la configuration TypeScript
npx tsc --init
Cela crée un fichier tsconfig.json qui configure comment TypeScript compile ton code.
Configuration de base (tsconfig.json)
{
"compilerOptions": {
"target": "ES2020", // Version JS cible
"module": "commonjs", // Système de modules
"strict": true, // Mode strict (recommandé)
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist", // Dossier de sortie
"rootDir": "./src" // Dossier source
}
}
Les types de base en TypeScript
1. Types primitifs
// String
let nom: string = "Alexandre";
let prenom: string = 'Jean';
// Number
let age: number = 25;
let prix: number = 19.99;
let hex: number = 0xf00d;
// Boolean
let estActif: boolean = true;
let estConnecte: boolean = false;
// Null et Undefined
let valeurNulle: null = null;
let valeurIndefinie: undefined = undefined;
// Any (à éviter autant que possible !)
let nimporteQuoi: any = "texte";
nimporteQuoi = 42; // ✅ Accepté mais défait le but de TypeScript
2. Arrays (tableaux)
// Tableau de nombres
let nombres: number[] = [1, 2, 3, 4, 5];
// Tableau de strings (syntaxe alternative)
let noms: Array<string> = ["Alice", "Bob", "Charlie"];
// Tableau mixte (union de types)
let mixte: (string | number)[] = ["Alice", 25, "Bob", 30];
// Tuple (tableau de taille et types fixes)
let utilisateur: [string, number] = ["Alexandre", 25];
console.log(utilisateur[0]); // "Alexandre"
console.log(utilisateur[1]); // 25
3. Objets et interfaces
// Interface pour définir la structure d'un objet
interface Utilisateur {
nom: string;
age: number;
email: string;
actif?: boolean; // ? = propriété optionnelle
}
const user: Utilisateur = {
nom: "Alexandre",
age: 25,
email: "alex@example.com"
// actif est optionnel, donc pas d'erreur
};
// Type alias (alternative aux interfaces)
type Produit = {
id: number;
nom: string;
prix: number;
enStock: boolean;
};
const produit: Produit = {
id: 1,
nom: "Laptop",
prix: 999,
enStock: true
};
4. Fonctions
// Fonction avec types de paramètres et type de retour
function addition(a: number, b: number): number {
return a + b;
}
// Fonction avec paramètre optionnel
function saluer(nom: string, titre?: string): string {
if (titre) {
return `Bonjour ${titre} ${nom}`;
}
return `Bonjour ${nom}`;
}
console.log(saluer("Dupont")); // "Bonjour Dupont"
console.log(saluer("Dupont", "M.")); // "Bonjour M. Dupont"
// Fonction avec paramètre par défaut
function creerUtilisateur(nom: string, role: string = "user"): void {
console.log(`Utilisateur ${nom} créé avec le rôle ${role}`);
}
// Arrow function avec types
const multiplier = (a: number, b: number): number => a * b;
// Fonction qui ne retourne rien (void)
function logMessage(message: string): void {
console.log(message);
}
Concepts avancés (mais essentiels)
1. Union Types (types union)
Une variable peut être de plusieurs types différents :
// ID peut être un nombre ou une string
type ID = number | string;
let userId: ID = 123; // ✅
userId = "user-abc"; // ✅
function afficherID(id: number | string): void {
if (typeof id === "string") {
console.log(`ID: ${id.toUpperCase()}`);
} else {
console.log(`ID: ${id}`);
}
}
2. Literal Types (types littéraux)
// Limite les valeurs possibles
type Direction = "nord" | "sud" | "est" | "ouest";
function deplacer(direction: Direction): void {
console.log(`Déplacement vers ${direction}`);
}
deplacer("nord"); // ✅
deplacer("haut"); // ❌ Erreur de compilation !
// Utile pour des configurations
type Environnement = "development" | "staging" | "production";
const env: Environnement = "production";
3. Type Assertions (assertions de type)
// Dire à TypeScript "fais-moi confiance, je sais ce que je fais"
let valeur: any = "ceci est une string";
let longueur: number = (valeur as string).length;
// Syntaxe alternative (attention, ne fonctionne pas en JSX)
let longueur2: number = (<string>valeur).length;
4. Type Guards (gardes de type)
function traiterReponse(reponse: string | number): void {
// Type guard avec typeof
if (typeof reponse === "string") {
console.log(reponse.toUpperCase()); // TypeScript sait que c'est une string
} else {
console.log(reponse.toFixed(2)); // TypeScript sait que c'est un number
}
}
// Type guard personnalisé
interface Chien {
aboyer(): void;
}
interface Chat {
miauler(): void;
}
function estUnChien(animal: Chien | Chat): animal is Chien {
return (animal as Chien).aboyer !== undefined;
}
function faireParler(animal: Chien | Chat): void {
if (estUnChien(animal)) {
animal.aboyer(); // TypeScript sait que c'est un Chien
} else {
animal.miauler(); // TypeScript sait que c'est un Chat
}
}
Classes et POO en TypeScript
class Utilisateur {
// Propriétés privées (non accessibles hors de la classe)
private id: number;
// Propriétés publiques (accessibles partout)
public nom: string;
// Propriétés protégées (accessibles dans la classe et les enfants)
protected email: string;
// Propriété readonly (lecture seule après initialisation)
readonly dateCreation: Date;
// Constructeur
constructor(id: number, nom: string, email: string) {
this.id = id;
this.nom = nom;
this.email = email;
this.dateCreation = new Date();
}
// Méthode publique
afficherInfo(): void {
console.log(`Utilisateur: ${this.nom} (${this.email})`);
}
// Getter
get identifiant(): number {
return this.id;
}
// Setter
set identifiant(nouvelId: number) {
if (nouvelId > 0) {
this.id = nouvelId;
}
}
}
// Héritage
class Admin extends Utilisateur {
private niveau: number;
constructor(id: number, nom: string, email: string, niveau: number) {
super(id, nom, email); // Appel du constructeur parent
this.niveau = niveau;
}
bannirUtilisateur(userId: number): void {
console.log(`Admin ${this.nom} a banni l'utilisateur ${userId}`);
}
}
const user = new Utilisateur(1, "Alice", "alice@example.com");
user.afficherInfo();
const admin = new Admin(2, "Bob", "bob@example.com", 5);
admin.bannirUtilisateur(10);
Génériques (Generics) : le pouvoir ultime
Les génériques permettent de créer des composants réutilisables qui fonctionnent avec n'importe quel type.
// Fonction générique simple
function premierElement<T>(tableau: T[]): T | undefined {
return tableau[0];
}
const premierNombre = premierElement([1, 2, 3]); // Type: number | undefined
const premiereString = premierElement(["a", "b", "c"]); // Type: string | undefined
// Interface générique
interface Reponse<T> {
data: T;
status: number;
message: string;
}
interface Utilisateur {
id: number;
nom: string;
}
const reponseUser: Reponse<Utilisateur> = {
data: { id: 1, nom: "Alice" },
status: 200,
message: "Succès"
};
const reponseString: Reponse<string> = {
data: "Hello",
status: 200,
message: "OK"
};
// Classe générique
class Collection<T> {
private items: T[] = [];
ajouter(item: T): void {
this.items.push(item);
}
retirer(item: T): void {
const index = this.items.indexOf(item);
if (index > -1) {
this.items.splice(index, 1);
}
}
obtenirTous(): T[] {
return this.items;
}
}
const nombresCollection = new Collection<number>();
nombresCollection.ajouter(1);
nombresCollection.ajouter(2);
const stringsCollection = new Collection<string>();
stringsCollection.ajouter("hello");
stringsCollection.ajouter("world");
Utility Types (types utilitaires) : gain de temps énorme
TypeScript fournit des types utilitaires pour transformer des types existants.
1. Partial<T> : rendre toutes les propriétés optionnelles
interface Utilisateur {
id: number;
nom: string;
email: string;
age: number;
}
// Toutes les propriétés deviennent optionnelles
function mettreAJourUtilisateur(
id: number,
updates: Partial<Utilisateur>
): void {
// On peut passer seulement les propriétés à modifier
}
mettreAJourUtilisateur(1, { nom: "Nouveau nom" }); // ✅
mettreAJourUtilisateur(1, { email: "new@example.com", age: 30 }); // ✅
2. Required<T> : rendre toutes les propriétés obligatoires
interface Config {
host?: string;
port?: number;
debug?: boolean;
}
const configComplete: Required<Config> = {
host: "localhost", // Obligatoire maintenant
port: 3000, // Obligatoire maintenant
debug: true // Obligatoire maintenant
};
3. Readonly<T> : rendre toutes les propriétés en lecture seule
interface Point {
x: number;
y: number;
}
const point: Readonly<Point> = { x: 10, y: 20 };
point.x = 5; // ❌ Erreur : propriété en lecture seule
4. Pick<T, K> : sélectionner certaines propriétés
interface Utilisateur {
id: number;
nom: string;
email: string;
motDePasse: string;
age: number;
}
// Ne garde que nom et email
type UtilisateurPublic = Pick<Utilisateur, "nom" | "email">;
const userPublic: UtilisateurPublic = {
nom: "Alice",
email: "alice@example.com"
// id, motDePasse, age ne sont pas requis
};
5. Omit<T, K> : exclure certaines propriétés
// Enlève motDePasse
type UtilisateurSansMotDePasse = Omit<Utilisateur, "motDePasse">;
const user: UtilisateurSansMotDePasse = {
id: 1,
nom: "Alice",
email: "alice@example.com",
age: 25
// motDePasse n'est pas présent
};
6. Record<K, T> : créer un objet avec des clés de type K et valeurs de type T
type Roles = "admin" | "user" | "guest";
const permissions: Record<Roles, string[]> = {
admin: ["read", "write", "delete"],
user: ["read", "write"],
guest: ["read"]
};
TypeScript avec JavaScript moderne (ES6+)
Destructuring avec types
interface Config {
host: string;
port: number;
debug: boolean;
}
const config: Config = { host: "localhost", port: 3000, debug: true };
// Destructuring avec types inférés
const { host, port } = config;
// Paramètre de fonction avec destructuring et types
function demarrerServeur({ host, port }: Config): void {
console.log(`Serveur démarré sur ${host}:${port}`);
}
Async/Await avec types
interface Utilisateur {
id: number;
nom: string;
}
// Fonction asynchrone qui retourne une Promise<Utilisateur>
async function recupererUtilisateur(id: number): Promise<Utilisateur> {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return data;
}
// Utilisation
async function main() {
try {
const user: Utilisateur = await recupererUtilisateur(1);
console.log(user.nom);
} catch (error) {
console.error("Erreur:", error);
}
}
Projet pratique : API REST typée avec TypeScript
Créons une petite API de gestion d'utilisateurs avec Express et TypeScript.
1. Setup du projet
mkdir api-typescript
cd api-typescript
npm init -y
npm install express
npm install --save-dev typescript @types/node @types/express ts-node-dev
# Initialiser TypeScript
npx tsc --init
2. Configuration (tsconfig.json)
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
3. Code source (src/index.ts)
import express, { Request, Response } from 'express';
const app = express();
app.use(express.json());
// Interface pour typer nos utilisateurs
interface Utilisateur {
id: number;
nom: string;
email: string;
age: number;
}
// Base de données simulée
let utilisateurs: Utilisateur[] = [
{ id: 1, nom: "Alice", email: "alice@example.com", age: 25 },
{ id: 2, nom: "Bob", email: "bob@example.com", age: 30 }
];
// GET /users - Récupérer tous les utilisateurs
app.get('/users', (req: Request, res: Response) => {
res.json(utilisateurs);
});
// GET /users/:id - Récupérer un utilisateur
app.get('/users/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const user = utilisateurs.find(u => u.id === id);
if (!user) {
return res.status(404).json({ message: "Utilisateur non trouvé" });
}
res.json(user);
});
// POST /users - Créer un utilisateur
app.post('/users', (req: Request, res: Response) => {
const { nom, email, age }: Partial<Utilisateur> = req.body;
// Validation
if (!nom || !email || !age) {
return res.status(400).json({ message: "Données manquantes" });
}
const nouvelUtilisateur: Utilisateur = {
id: utilisateurs.length + 1,
nom,
email,
age
};
utilisateurs.push(nouvelUtilisateur);
res.status(201).json(nouvelUtilisateur);
});
// PUT /users/:id - Mettre à jour un utilisateur
app.put('/users/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const updates: Partial<Utilisateur> = req.body;
const index = utilisateurs.findIndex(u => u.id === id);
if (index === -1) {
return res.status(404).json({ message: "Utilisateur non trouvé" });
}
utilisateurs[index] = { ...utilisateurs[index], ...updates };
res.json(utilisateurs[index]);
});
// DELETE /users/:id - Supprimer un utilisateur
app.delete('/users/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const index = utilisateurs.findIndex(u => u.id === id);
if (index === -1) {
return res.status(404).json({ message: "Utilisateur non trouvé" });
}
utilisateurs.splice(index, 1);
res.status(204).send();
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Serveur démarré sur http://localhost:${PORT}`);
});
4. Script de développement (package.json)
{
"scripts": {
"dev": "ts-node-dev --respawn src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}
5. Lancer le serveur
npm run dev
Les erreurs TypeScript courantes et comment les résoudre
1. "Type 'X' is not assignable to type 'Y'"
let age: number = "25"; // ❌ Erreur
// Solution : convertir le type
let age: number = parseInt("25"); // ✅
2. "Object is possibly 'undefined'"
const user = users.find(u => u.id === 1);
console.log(user.nom); // ❌ user peut être undefined
// Solution 1 : vérifier
if (user) {
console.log(user.nom); // ✅
}
// Solution 2 : optional chaining
console.log(user?.nom); // ✅
// Solution 3 : valeur par défaut
console.log(user?.nom ?? "Inconnu"); // ✅
3. "Property 'X' does not exist on type 'Y'"
interface User {
nom: string;
}
const user: User = { nom: "Alice" };
console.log(user.age); // ❌ age n'existe pas sur User
// Solution : ajouter la propriété à l'interface
interface User {
nom: string;
age?: number; // Optionnel
}
Outils et ressources pour progresser en TypeScript
- 📚 Documentation officielle TypeScript : typescriptlang.org
- 🎓 TypeScript Handbook : guide complet officiel
- 💻 TypeScript Playground : tester TypeScript en ligne
- 🎬 YouTube : Fireship (TypeScript en 100 secondes), Ben Awad, Academind
- 📖 Effective TypeScript (livre) : 62 façons d'améliorer ton code TypeScript
- 🛠️ VS Code : meilleur IDE pour TypeScript (support natif)
- 🔧 ESLint + Prettier : linter et formatter pour code propre
Quand utiliser TypeScript ?
✅ TypeScript est idéal pour :
- Projets moyens à grands (+ de 1000 lignes)
- Équipes de développeurs (documentation via les types)
- Applications critiques (banque, santé, e-commerce)
- Bases de code à maintenir sur le long terme
- APIs et backends (Express, NestJS, Fastify)
- Applications frontend (React, Angular, Vue)
❌ TypeScript peut être overkill pour :
- Scripts jetables (moins de 100 lignes)
- Prototypes rapides (MVP en 2 jours)
- Projets solo très simples
- Si toute l'équipe refuse de l'apprendre
Conclusion : TypeScript vaut-il vraiment le coup ?
OUI, sans hésitation. Après quelques années de JavaScript pur, passer à TypeScript a littéralement transformé ma façon de coder. Les bugs stupides qui me prenaient 2 heures à debugger ? Attrapés en 2 secondes par le compilateur. L'autocomplétion intelligente ? Je code 2x plus vite. La refactorisation ? Je renomme une propriété et TypeScript met à jour automatiquement les 50 fichiers qui l'utilisent.
Certes, il y a une courbe d'apprentissage. Les premiers jours, tu vas peut-être râler contre les erreurs de type. Mais après 2 semaines, tu ne pourras plus revenir en arrière. Coder en JavaScript sans types, c'est comme conduire sans ceinture : techniquement possible, mais pourquoi prendre le risque ?
Mon conseil : Si tu hésites encore, crée un petit projet TypeScript ce week-end. Une API REST, une To-Do App, un petit jeu... N'importe quoi pour tester. Je te parie que dans 2 semaines, tous tes nouveaux projets seront en TypeScript.
TypeScript, ce n'est pas "JavaScript avec des contraintes supplémentaires". C'est JavaScript avec des super-pouvoirs. Et en 2025, c'est devenu un must-have pour tout développeur JavaScript sérieux.
Bienvenue dans le monde du JavaScript typé. Tu vas adorer ! 🚀