Injection de Dépendances en TypeScript : Guide Complet avec Exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Qu'est-ce que l'Injection de Dépendances en TypeScript et pourquoi en a-t-on besoin ?



L'Injection de Dépendances (DI) est un pattern de conception qui implémente le principe d'inversion de contrôle (Inversion of Control, IoC). Au lieu que l'objet crée lui-même ses dépendances, celles-ci sont "injectées" de l'extérieur. En TypeScript, ce pattern est particulièrement utile grâce au typage strict et aux possibilités des décorateurs.



Imaginez que vous construisez une application pour une boutique en ligne. Vous avez une classe OrderService qui doit envoyer des notifications. Sans DI, elle serait fortement liée à un moyen d'envoi spécifique (par exemple, Email). Avec DI, vous pouvez facilement remplacer Email par SMS ou des notifications Push, sans modifier le code de OrderService.



Pourquoi utiliser DI en TypeScript ?

  • Testabilité : Il est facile de remplacer les services réels par des objets mock dans les tests unitaires.
  • Flexibilité : Le système devient modulaire, les dépendances peuvent être changées sans modifier le code client.
  • Simplification de la maintenance : Chaque classe est responsable uniquement de sa logique métier, et non de la création d'autres objets.
  • Sécurité de typage : TypeScript vérifie les types à la compilation, ce qui réduit le nombre d'erreurs lors de l'exécution.


Implémentation de base de DI en TypeScript sans frameworks



Commençons par un exemple simple. Créons une interface pour le service de notifications et deux de ses implémentations.



// Définissons l'interfaceinterface INotificationService {    send(message: string): void;}

// Implémentation pour Emailclass EmailNotificationService implements INotificationService { send(message: string): void { console.log(`Envoi Email : ${message}`); }}

// Implémentation pour SMSclass SMSNotificationService implements INotificationService { send(message: string): void { console.log(`Envoi SMS : ${message}`); }}

// Classe qui utilise DIclass OrderService { constructor(private notificationService: INotificationService) {}

processOrder(orderId: number): void { // Logique de traitement de commande this.notificationService.send(`Commande #${orderId} traitée`); }}

// Utilisationconst emailService = new EmailNotificationService();const orderService = new OrderService(emailService);orderService.processOrder(123); // Envoi Email : Commande #123 traitée


Dans cet exemple, OrderService ne sait pas quel service de notifications est utilisé. Il appelle simplement la méthode send via l'interface.



DI avancé : Création d'un conteneur IoC simple



Pour les grands projets, l'injection manuelle de dépendances devient lourde. C'est là qu'intervient le conteneur IoC. Voyons comment l'implémenter en utilisant les décorateurs TypeScript.



Étape 1 : Activez le support des décorateurs dans tsconfig.json

{    "compilerOptions": {        "experimentalDecorators": true,        "emitDecoratorMetadata": true    }}


Étape 2 : Créez le conteneur DI

// di-container.tstype Constructor<T> = new (...args: any[]) => T;

class DIContainer { private services = new Map<string, any>();

register<T>(token: string, implementation: Constructor<T>): void { this.services.set(token, implementation); }

resolve<T>(token: string): T { const Implementation = this.services.get(token); if (!Implementation) { throw new Error(`Le service "${token}" n'est pas enregistré`); }

// Obtenons les types des paramètres du constructeur via la réflexion const paramTypes: Constructor<any>[] = Reflect.getMetadata('design:paramtypes', Implementation) || [];

// Résolvons récursivement les dépendances const dependencies = param

Blogs

Book Recommendations