Typescript fondamentaux
Thème :
Intermédiaire
1 vues ·1/14 leçons01 - Introduction TypeScript : Du JavaScript Typé au Code Robuste
1.1 Qu’est-ce que TypeScript en 2025 ?
Définition et Philosophie
TypeScript est un sur-ensemble de JavaScript qui ajoute des types statiques au langage. Créé par Microsoft en 2012, il est devenu le standard de facto pour le développement JavaScript moderne.
// JavaScript classique
function calculerAge(nom, anneeNaissance) {
const age = new Date().getFullYear() - anneeNaissance;
return `${nom} a ${age} ans`;
}
// TypeScript avec types
function calculerAge(nom: string, anneeNaissance: number): string {
const age: number = new Date().getFullYear() - anneeNaissance;
return `${nom} a ${age} ans`;
}
Pourquoi TypeScript en 2025 ?
- Sécurité du type : Erreurs détectées à la compilation
- IntelliSense avancé : Auto-complétion contextuelle
- Refactoring sûr : Renommage automatique et fiable
- Documentation vivante : Les types servent de documentation
- Adoption massive : 95%+ des projets JavaScript modernes
Écosystème TypeScript 2025
- TypeScript 5.4+ : Dernières fonctionnalités
- IDE support : VS Code, WebStorm, Vim
- Build tools : Vite, esbuild, SWC
- Framework integration : React, Vue, Angular, Svelte
1.2 Installation et Configuration
Installation Globale
# Installation avec npm
npm install -g typescript
# Installation avec pnpm
pnpm add -g typescript
# Installation avec yarn
yarn global add typescript
# Vérification de l'installation
tsc --version
Installation de Projet
# Projet TypeScript initial
npm init -y
npm install typescript --save-dev
npm install @types/node --save-dev
# Configuration TypeScript
npx tsc --init
tsconfig.json Essentiel
{
"compilerOptions": {
"target": "ES2024",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"sourceMap": true,
"removeComments": false,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
1.3 Types de Base
Types Primitifs
// Types de base
let nom: string = "Alice";
let age: number = 25;
let estActif: boolean = true;
let rien: null = null;
let nonDefini: undefined = undefined;
let unique: symbol = Symbol("id");
// Types spéciaux
let grandNombre: bigint = 9007199254740991n;
let donneesBinaires: any = { /* n'importe quoi */ };
let inconnu: unknown = /* valeur inconnue */;
// Tableaux typés
let nombres: number[] = [1, 2, 3, 4, 5];
let noms: Array<string> = ["Alice", "Bob", "Charlie"];
Types Spéciaux
// any : Désactive le typage (à éviter)
let flexible: any = "peut être n'importe quoi";
// unknown : Type sécurisé pour valeurs inconnues
let donnee: unknown = JSON.parse(jsonString);
// never : Type qui n'arrive jamais
function erreur(message: string): never {
throw new Error(message);
}
// void : Absence de retour
function logger(message: string): void {
console.log(message);
}
Tuple et Enum
// Tuple : Tableau avec types fixes
let coordonnees: [number, number] = [10, 20];
let personne: [string, number, boolean] = ['Alice', 25, true];
// Enum : Ensemble de constantes nommées
enum Statut {
EnAttente = 'en_attente',
EnCours = 'en_cours',
Termine = 'termine',
}
let statutCommande: Statut = Statut.EnCours;
1.4 Interfaces et Types d’Objets
Définition d’Interface
interface Utilisateur {
id: number;
nom: string;
email: string;
age?: number; // Optionnel
readonly dateCreation: Date; // Lecture seule
}
const utilisateur: Utilisateur = {
id: 1,
nom: 'Alice',
email: 'alice@example.com',
dateCreation: new Date(),
};
Types Union et Intersection
// Union : Un type parmi plusieurs
type ID = string | number;
let userId: ID = 'user123'; // ou 123
type Statut = 'en_attente' | 'en_cours' | 'termine';
// Intersection : Combinaison de types
interface Personne {
nom: string;
age: number;
}
interface Employe {
salaire: number;
poste: string;
}
type EmployePersonne = Personne & Employe;
const employe: EmployePersonne = {
nom: 'Alice',
age: 30,
salaire: 50000,
poste: 'Développeuse',
};
Types Avancés
// Type conditionnel
type NonNull<T> = T extends null ? never : T;
type Stringify<T> = {
[K in keyof T]: string;
};
// Type mappé
type Partiel<T> = {
[P in keyof T]?: T[P];
};
interface UtilisateurComplet {
id: number;
nom: string;
email: string;
age: number;
}
type UtilisateurPartiel = Partiel<UtilisateurComplet>;
1.5 Fonctions Typées
Typage des Fonctions
// Fonction fléchée typée
const addition = (a: number, b: number): number => a + b;
// Fonction classique typée
function multiplier(x: number, y: number): number {
return x * y;
}
// Paramètres optionnels
function saluer(nom: string, titre?: string): string {
if (titre) {
return `Bonjour ${titre} ${nom}`;
}
return `Bonjour ${nom}`;
}
// Paramètres par défaut
function creerCompte(nom: string, email: string, role: string = 'utilisateur'): void {
console.log(`Compte créé pour ${nom} (${email}) avec le rôle ${role}`);
}
Fonctions Génériques
// Fonction générique simple
function identite<T>(valeur: T): T {
return valeur;
}
const numero = identite(42); // number
const texte = identite('hello'); // string
// Contraintes génériques
function premierElement<T>(tableau: T[]): T | undefined {
return tableau.length > 0 ? tableau[0] : undefined;
}
// Utilitaires génériques
interface Repository<T> {
trouver(id: number): T | null;
sauvegarder(item: T): void;
supprimer(id: number): boolean;
}
1.6 Classes en TypeScript
Classe de Base
class Animal {
// Propriétés publiques
public nom: string;
protected age: number;
private espece: string;
// Constructeur typé
constructor(nom: string, age: number, espece: string) {
this.nom = nom;
this.age = age;
this.espece = espece;
}
// Méthode publique
public presenter(): string {
return `Je suis ${this.nom}, un ${this.espece} de ${this.age} ans`;
}
// Méthode protégée
protected crier(): void {
console.log(`${this.nom} fait du bruit !`);
}
}
// Héritage
class Chien extends Animal {
private race: string;
constructor(nom: string, age: number, race: string) {
super(nom, age, 'chien');
this.race = race;
}
public aboyer(): void {
console.log(`${this.nom} aboie !`);
this.crier(); // Appel méthode protégée
}
// Redéfinition de méthode
public presenter(): string {
return `${super.presenter()} et je suis un ${this.race}`;
}
}
Modificateurs d’Accès
class CompteBancaire {
public titulaire: string;
private solde: number;
protected numeroCompte: string;
readonly dateOuverture: Date;
constructor(titulaire: string, depotInitial: number) {
this.titulaire = titulaire;
this.solde = depotInitial;
this.numeroCompte = this.genererNumero();
this.dateOuverture = new Date();
}
public deposer(montant: number): void {
if (montant > 0) {
this.solde += montant;
}
}
private genererNumero(): string {
return `FR${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
}
protected verifierSolde(): boolean {
return this.solde >= 0;
}
}
1.7 Gestion des Erreurs
Types d’Erreurs Personnalisés
// Erreur personnalisée
class ErreurValidation extends Error {
public code: string;
public champ: string;
constructor(message: string, code: string, champ: string) {
super(message);
this.name = 'ErreurValidation';
this.code = code;
this.champ = champ;
}
}
// Utilisation des erreurs typées
function validerEmail(email: string): void {
if (!email.includes('@')) {
throw new ErreurValidation('Email invalide', 'EMAIL_INVALIDE', 'email');
}
}
Union de Types d’Erreurs
type ErreurAPI = ErreurValidation | ErreurReseau | ErreurAuthentification;
class GestionnaireErreurs {
public gererErreur(error: ErreurAPI): void {
if (error instanceof ErreurValidation) {
console.error(`Erreur de validation : ${error.champ}`);
} else if (error instanceof ErreurReseau) {
console.error(`Erreur réseau : ${error.message}`);
}
}
}
1.8 Utilitaires TypeScript
Type Guards
// Type guard function
function estString(valeur: unknown): valeur is string {
return typeof valeur === 'string';
}
function estNombre(valeur: unknown): valeur is number {
return typeof valeur === 'number';
}
// Utilisation avec type narrowing
function traiterValeur(valeur: unknown): void {
if (estString(valeur)) {
console.log(valeur.toUpperCase()); // TypeScript sait que c'est une string
} else if (estNombre(valeur)) {
console.log(valeur.toFixed(2)); // TypeScript sait que c'est un number
}
}
Types Utilitaires
// Type utilitaire pour rendre toutes les propriétés optionnelles
type Partiel<T> = {
[P in keyof T]?: T[P];
};
// Type utilitaire pour rendre les propriétés requises
type Requis<T> = {
[P in keyof T]-?: T[P];
};
// Type utilitaire pour extraire les propriétés
type ProprietesSeulement<T> = {
[K in keyof T]: T[K];
};
// Application
interface UtilisateurComplet {
id: number;
nom: string;
email: string;
age: number;
}
type UtilisateurCreation = Partiel<UtilisateurComplet>;
type UtilisateurLecture = ProprietesSeulement<UtilisateurComplet>;
🎯 TP 1 : Système de Gestion d’Utilisateurs avec TypeScript
Objectifs
- Appliquer les concepts fondamentaux de TypeScript
- Créer des interfaces et types robustes
- Implémenter la validation de types
- Utiliser les classes et l’héritage
- Gérer les erreurs de manière typée
Fonctionnalités Requises
1. Modèle de Données
interface Utilisateur {
id: number;
nom: string;
email: string;
age: number;
dateCreation: Date;
derniereConnexion?: Date;
}
interface Compte {
id: number;
idUtilisateur: number;
type: 'admin' | 'utilisateur' | 'moderateur';
statut: 'actif' | 'suspendu' | 'ferme';
dateCreation: Date;
}
2. Classes de Service
class ServiceUtilisateur {
private utilisateurs: Utilisateur[] = [];
private prochainId: number = 1;
public creerUtilisateur(donnees: Omit<Utilisateur, 'id'>): Utilisateur {
const utilisateur: Utilisateur = {
id: this.prochainId++,
...donnees,
dateCreation: new Date(),
};
this.utilisateurs.push(utilisateur);
return utilisateur;
}
public trouverUtilisateur(id: number): Utilisateur | null {
return this.utilisateurs.find((u) => u.id === id) || null;
}
public listerUtilisateurs(): Utilisateur[] {
return [...this.utilisateurs];
}
}
3. Validation de Types
class ValidateurUtilisateur {
public static validerEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
public static validerAge(age: number): boolean {
return age >= 0 && age <= 150;
}
public static validerNom(nom: string): boolean {
return nom.length >= 2 && nom.length <= 50;
}
}
4. Gestion des Erreurs
class ErreurUtilisateur extends Error {
constructor(
message: string,
public code: string,
public champ?: string,
) {
super(message);
this.name = 'ErreurUtilisateur';
}
}
class GestionnaireErreursUtilisateur {
public static gerer(error: unknown): never {
if (error instanceof ErreurUtilisateur) {
console.error(`Erreur ${error.code}: ${error.message}`);
throw error;
}
throw new ErreurUtilisateur('Erreur inconnue lors du traitement', 'ERREUR_INCONNUE');
}
}
5. Interface Utilisateur
// Interface pour le formulaire de création
interface FormulaireCreationUtilisateur {
nom: string;
email: string;
motDePasse: string;
confirmationMotDePasse: string;
age: string;
}
// Type pour les réponses API
interface ReponseAPI<T> {
succes: boolean;
donnees?: T;
erreur?: {
code: string;
message: string;
champ?: string;
};
}
Instructions d’Implémentation
-
Créer la structure du projet
typescript-tp/ ├── src/ │ ├── models/ │ │ ├── Utilisateur.ts │ │ └── Compte.ts │ ├── services/ │ │ └── ServiceUtilisateur.ts │ ├── validators/ │ │ └── ValidateurUtilisateur.ts │ ├── errors/ │ │ └── ErreurUtilisateur.ts │ ├── types/ │ │ └── index.ts │ └── index.ts ├── tsconfig.json └── package.json -
Implémenter les classes et interfaces
- Créer les interfaces
UtilisateuretCompte - Implémenter la classe
ServiceUtilisateuravec méthodes CRUD - Ajouter la classe
ValidateurUtilisateuravec validation de types - Créer la classe
ErreurUtilisateurpour la gestion d’erreurs
- Créer les interfaces
-
Ajouter les types utilitaires
Partiel<T>pour les formulairesRequis<T>pour les validations- Types union pour les statuts et rôles
-
Créer des tests
- Tests unitaires pour chaque classe
- Tests de validation de types
- Tests de gestion d’erreurs
-
Compiler et vérifier
# Compilation npx tsc # Watch mode npx tsc --watch # Vérification des types npx tsc --noEmit
Critères de Réussite
- ✅ Typage strict : Aucune utilisation de
any - ✅ Interfaces complètes : Toutes les propriétés typées
- ✅ Validation robuste : Vérification des types à l’exécution
- ✅ Gestion d’erreurs : Types d’erreurs personnalisées
- ✅ Code compilé : Zéro erreur de compilation TypeScript
- ✅ Tests passants : Couverture minimale de 80%
Extensions Possibles
- Persistance : Sauvegarde des utilisateurs en localStorage
- Authentification : Système de login avec JWT
- Permissions : Rôles et droits d’accès
- API REST : Endpoints pour la gestion des utilisateurs
- Interface React : Composants React typés
📚 Ressources Complémentaires
Documentation Officielle
Outils Recommandés
- VS Code : Meilleur support TypeScript
- TypeScript Playground : Essai en ligne
- DefinitelyTyped : Types pour les librairies JavaScript
Bonnes Pratiques
- Toujours activer le mode strict
- Préférer les interfaces aux types
- Utiliser les types guards pour la sécurité
- Documenter les types complexes
- Éviter
anyautant que possible
Cette leçon pose les fondations de TypeScript en se basant sur les concepts JavaScript déjà maîtrisés, en ajoutant la sécurité du typage statique.
Prêt à passer à la suite ?
Vous avez terminé cette leçon sur 01 - Introduction TypeScript : Du JavaScript Typé au Code Robuste. Continuez votre apprentissage avec la prochaine leçon ou explorez d'autres formations.