Principes SOLID en TypeScript : niveau avancé 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

Principes SOLID en TypeScript : théorie et pratique de niveau avancé

\n\n

SOLID — ce sont cinq principes fondamentaux de conception orientée objet qui permettent de créer un code flexible, maintenable et évolutif. En TypeScript, grâce au typage strict, aux interfaces et aux classes abstraites, la mise en œuvre de ces principes devient particulièrement efficace. Dans cet article, nous analyserons chaque principe à un niveau avancé avec des exemples concrets en TypeScript.

\n\n

1. Single Responsibility Principle (SRP) — Principe de responsabilité unique

\n\n

Théorie : Chaque classe doit avoir une seule raison de changer. En TypeScript, cela signifie qu'un module est responsable d'exactement une fonctionnalité.

\n\n

Pratique avancée : La violation du SRP se manifeste souvent par des « objets divins » (God Objects). Utilisez la composition et la délégation.

\n\n
// ❌ Violation du SRP : la classe est responsable des données, de la validation et de la sauvegarde\nclass UserService {\n  constructor(private user: User) {}\n\n  validateEmail(email: string): boolean {\n    return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n  }\n\n  saveToDatabase(): void {\n    // logique de sauvegarde\n  }\n\n  sendWelcomeEmail(): void {\n    // logique d'envoi\n  }\n}\n\n// ✅ SRP : séparation des responsabilités\ninterface IEmailValidator {\n  isValid(email: string): boolean;\n}\n\ninterface IUserRepository {\n  save(user: User): Promise<void>;\n}\n\ninterface INotificationService {\n  sendWelcome(user: User): Promise<void>;\n}\n\nclass UserRegistrationService {\n  constructor(\n    private validator: IEmailValidator,\n    private repository: IUserRepository,\n    private notifier: INotificationService\n  ) {}\n\n  async register(user: User): Promise<void> {\n    if (!this.validator.isValid(user.email)) {\n      throw new Error('Email invalide');\n    }\n    await this.repository.save(user);\n    await this.notifier.sendWelcome(user);\n  }\n}
\n\n

2. Open/Closed Principle (OCP) — Principe d'ouverture/fermeture

\n\n

Théorie : Les classes doivent être ouvertes à l'extension, mais fermées à la modification. En TypeScript, cela est réalisé via des classes abstraites et des interfaces.

\n\n

Pratique avancée : Utilisez le patron « Stratégie » (Strategy) pour implémenter l'OCP.

\n\n
// ❌ Violation de l'OCP : l'ajout d'un nouveau type de rapport nécessite de modifier la classe\nclass ReportGenerator {\n  generate(data: any[], type: string): string {\n    if (type === 'csv') {\n      return data.map(row => row.join(',')).join('\\n');\n    } else if (type === 'json') {\n      return JSON.stringify(data);\n    }\n    // lors de l'ajout de 'xml' — on modifie cette méthode\n    throw new Error('Format non supporté');\n  }\n}\n\n// ✅ OCP : utilisation du polymorphisme\ninterface IReportFormatter {\n  format(data: any[]): string;\n}\n\nclass CsvFormatter implements IReportFormatter {\n  format(data: any[]): string {\n    return data.map(row => row.join(',')).join('\\n');\n  }\n}\n\nclass JsonFormatter implements IReportFormatter {\n  format(data: any[]): string {\n    return JSON.stringify(data);\n  }\n}\n\nclass XmlFormatter implements IReportFormatter {\n  format(data: any[]): string {\n    // implémentation pour XML\n    return '<data>...</data>';\n  }\n}\n\nclass ReportGeneratorOCP {\n  constructor(private formatter: IReportFormatter) {}\n\n  generate(data: any[]): string {\n    return this.formatter.format(data);\n  }\n}\n\n// Utilisation : extension sans modification\nconst csvReport = new ReportGeneratorOCP(new CsvFormatter());\nconst jsonReport = new ReportGeneratorOCP(new JsonFormatter());
\n\n

3. Liskov Substitution Principle (LSP) — Principe de substitution de Barbara Liskov

\n\n

Théorie : Les objets d'un programme doivent être remplaçables par des instances de leurs sous-types sans altérer la correction du programme. En TypeScript, cela est particulièrement critique en raison du typage nominatif.

Blogs

Book Recommendations