Code propre en TypeScript : règles, exemples et astuces

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

Pourquoi le code propre en TypeScript n'est pas un luxe, mais une nécessité

Chaque développeur a déjà vécu cette situation : vous ouvrez un projet écrit il y a quelques mois et vous ne comprenez pas ce qui s'y passe. Les variables s'appellent a, b, data, les fonctions font 200 lignes, et les types sont placés de temps en temps. Cela vous dit quelque chose ?

TypeScript nous offre un outil puissant : le typage statique. Mais à lui seul, il ne rend pas le code propre. On peut écrire du code horrible aussi bien en TypeScript que dans n'importe quel autre langage. Le code propre est une discipline, un style et un respect de soi-même et de ses collègues.

Dans cet article, nous allons voir comment écrire du code propre en TypeScript, qui sera facile à lire, à maintenir et à faire évoluer. Vous découvrirez les principes SOLID, le typage strict, le nommage, le travail avec les interfaces et bien plus encore. C'est parti !



1. Le nommage : le visage de votre code

Un bon nommage des variables, fonctions et classes représente 50% du succès. Un bon nom doit répondre aux questions : "Qu'est-ce que c'est ?" ou "Que fait cette fonction ?".



Variables et constantes

Utilisez des noms et le camelCase. Évitez les noms d'une seule lettre (sauf dans les boucles).

// Mauvaisconst d = new Date();const u = users.find(u => u.id === 5);

// Bonconst currentDate = new Date();const activeUser = users.find(user => user.id === 5);


Fonctions

Les noms de fonctions doivent commencer par un verbe. Cela indique immédiatement l'action effectuée.

// Mauvaisfunction data(id: number) { ... }

// Bonfunction fetchUserData(id: number): Promise<UserData> { ... }


Classes et interfaces

Les classes sont des noms en PascalCase. Les interfaces aussi, mais souvent avec le préfixe I (bien que la communauté soit divisée). Il est préférable de donner simplement un nom clair sans préfixe.

// Mauvaisinterface IUser {  name: string;}

// Boninterface User { name: string; email: string;}


2. Le typage strict : votre meilleur ami

TypeScript est conçu pour que les types travaillent pour vous. N'utilisez pas any sans nécessité absolue. Chaque fois que vous écrivez any, vous désactivez la protection du compilateur.



Évitez any

// Mauvaisfunction process(data: any) {  return data.name;}

// Boninterface Item { name: string; price: number;}

function process(data: Item): string { return data.name;}


Utilisez les types Union et Intersection

Lorsqu'une variable peut accepter plusieurs types, utilisez Union (|). Pour la combinaison, utilisez Intersection (&).

type Status = 'active' | 'inactive' | 'pending';type AdminUser = User & { role: 'admin' };


Les génériques : fonctions universelles

Les génériques permettent d'écrire du code flexible sans perdre le typage.

function firstElement<T>(arr: T[]): T | undefined {  return arr[0];}

const num = firstElement([1, 2, 3]); // numberconst str = firstElement(['a', 'b']); // string


3. SOLID : des principes pour les adultes

Les principes SOLID aident à construire une architecture flexible et maintenable. Examinons chacun d'eux avec des exemples en TypeScript.



Responsabilité unique (SRP)

Une classe ou une fonction ne doit avoir qu'une seule raison de changer.

// Mauvais : la classe fait toutclass UserService {  createUser() { ... }  sendEmail() { ... }  generateReport() { ... }}

// Bon : on sépare les responsabilitésclass UserCreator { ... }class EmailService { ... }class ReportGenerator { ... }


Ouvert/Fermé (OCP)

Les classes sont ouvertes à l'extension, mais fermées à la modification. Utilisez des interfaces et l'héritage.



Substitution de Liskov (LSP)

Les sous-classes doivent pouvoir remplacer la classe de base sans modifier le comportement du programme.



Ségrégation des interfaces (ISP)

Les interfaces doivent être spécifiques plutôt que générales. Il vaut mieux plusieurs interfaces spécialisées qu'une seule interface monolithique.



Inversion des dépendances (DIP)

Dépendre des abstractions, pas des implémentations concrètes. Utilisez l'injection de dépendances.



4. Motifs de conception utiles en TypeScript

Les motifs de conception (patterns) sont des solutions éprouvées à des problèmes récurrents. En voici quelques-uns particulièrement utiles en TypeScript.



Pattern Singleton

Garantit qu'une classe n'a qu'une seule instance.

class Database {  private static instance: Database;  private constructor() {}

static getInstance(): Database { if (!Database.instance) { Database.instance = new Database(); } return Database.instance; }}


Pattern Factory

Crée des objets sans spécifier la classe exacte.

interface Animal {  speak(): void;}

class Dog implements Animal { speak() { console.log('Woof!'); }}

class Cat implements Animal { speak() { console.log('Meow!'); }}

class AnimalFactory { static create(type: 'dog' | 'cat'): Animal { if (type === 'dog') return new Dog(); return new Cat(); }}


Pattern Decorator

Ajoute dynamiquement des fonctionnalités à un objet.

function log(target: any, key: string, descriptor: PropertyDescriptor) {  const original = descriptor.value;  descriptor.value = function(...args: any[]) {    console.log(`Appel de ${key} avec`, args);    return original.apply(this, args);  };}

class Calculator { @log add(a: number, b: number): number { return a + b; }}


5. Travailler avec les promesses et l'asynchrone

Le code asynchrone en TypeScript peut devenir un véritable désordre. Utilisez async/await et gérez correctement les erreurs.



Évitez les promesses chaînées

// Mauvaisfunction fetchData() {  return fetch('/api/data')    .then(response => response.json())    .then(data => process(data))    .catch(error => console.error(error));}

// Bonasync function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); return process(data); } catch (error) { console.error(error); }}


Gestion des erreurs typée

Créez des classes d'erreur personnalisées pour un meilleur contrôle.

class ApiError extends Error {  constructor(public statusCode: number, message: string) {    super(message);  }}

async function getUser(id: number): Promise<User> { const response = await fetch(`/api/users/${id}`); if (!response.ok) { throw new ApiError(response.status, 'Erreur lors de la récupération de l\\'utilisateur'); } return response.json();}


6. Tests : votre filet de sécurité

Le code propre doit être testé. TypeScript s'intègre parfaitement avec Jest, Vitest et d'autres frameworks de test.



Exemple de test unitaire

// math.tsexport function add(a: number, b: number): number {  return a + b;}

// math.test.tsimport { add } from './math';

describe('add', () => { it('devrait additionner deux nombres', () => { expect(add(2, 3)).toBe(5); });

it('devrait gérer les nombres négatifs', () => { expect(add(-1, 1)).toBe(0); });});


Conclusion

Écrire du code propre en TypeScript n'est pas seulement une question de syntaxe. C'est une approche qui inclut le nommage, le typage, l'architecture, les motifs et les tests. Commencez par appliquer ces règles une par une, et vous verrez comment la qualité de votre code s'améliore.

N'oubliez pas : le code propre n'est pas un luxe, c'est un investissement dans l'avenir de votre projet. Bonne chance dans votre développement !

Blogs

Book Recommendations