Clean Code en TypeScript : principes et exemples pratiques
\n\nChaque développeur a déjà vécu cette situation où, un mois après avoir écrit du code, son propre script lui semble étranger et incompréhensible. Dans le monde de TypeScript, où le typage strict offre un avantage, les principes du Clean Code deviennent particulièrement importants. Un code propre n'est pas seulement une question d'esthétique, mais un outil pour réduire les bugs, accélérer le développement et faciliter le travail en équipe. Dans cet article, nous allons analyser les principes clés du Clean Code en TypeScript avec des exemples concrets qui vous aideront à écrire un code facile à lire, tester et maintenir.
\n\n1. Nommage : dites ce que fait la variable
\n\nLa première chose qu'un développeur voit, ce sont les noms des variables, fonctions et classes. Un mauvais nom oblige le lecteur à perdre du temps à déchiffrer. En TypeScript, avec son système de types, le nom doit être auto-documenté.
\n\nMauvais exemple :
\nconst d = new Date();\nconst arr = [1, 2, 3];\nfunction proc(x: number, y: number) {\n return x * y;\n}\n\nBon exemple :
\nconst currentDate = new Date();\nconst userScores: number[] = [1, 2, 3];\nfunction calculateArea(width: number, height: number): number {\n return width * height;\n}\n\nUtilisez des noms pour les variables et des verbes pour les fonctions. Évitez les abréviations (sauf celles couramment acceptées comme id ou url). TypeScript permet d'ajouter des types, mais le nom doit quand même refléter l'essence.
2. Fonctions : petites, propres et prévisibles
\n\nUne fonction ne doit faire qu'une seule chose. Si vous ne pouvez pas trouver un nom court pour une fonction, c'est probablement qu'elle en fait trop. Il est également important d'éviter les effets de bord.
\n\nPrincipe de responsabilité unique (SRP) au niveau des fonctions :
\n\n// Mauvais : la fonction fait tout à la fois\nfunction processUserData(user: User): void {\n // Validation\n if (!user.email) throw new Error('Email required');\n // Sauvegarde en BDD\n database.save(user);\n // Envoi d'email\n emailService.sendWelcome(user.email);\n}\n\n// Bon : on sépare les responsabilités\nfunction validateUser(user: User): boolean {\n return user.email !== undefined;\n}\n\nfunction saveUser(user: User): void {\n database.save(user);\n}\n\nfunction sendWelcomeEmail(email: string): void {\n emailService.send(email);\n}\n\nfunction processUser(user: User): void {\n if (!validateUser(user)) {\n throw new Error('Invalid user data');\n }\n saveUser(user);\n sendWelcomeEmail(user.email);\n}\n\nÉvitez également un grand nombre de paramètres. S'il y en a plus de deux, regroupez-les dans un objet :
\n\n// Mauvais\nfunction createUser(name: string, email: string, age: number, isAdmin: boolean): void {}\n\n// Bon\ninterface CreateUserParams {\n name: string;\n email: string;\n age: number;\n isAdmin: boolean;\n}\n\nfunction createUser(params: CreateUserParams): void {}\n\n3. Typage : utilisez pleinement les possibilités de TypeScript
\n\nL'un des principaux avantages de TypeScript est le typage strict. Mais de nombreux développeurs utilisent any comme une béquille, tuant tout l'intérêt. Un code propre en TypeScript est un code où les types sont explicitement décrits, et non devinés.
Évitez any :
// Mauvais\nfunction getData(): any {\n return fetch('/api/data');\n}\n\n// Bon\ninterface ApiResponse {\n id: number;\n title: string;\n}\n\nasync function getData(): Promise<ApiResponse> {\n const response = await fetch('/api/data');\n return response.json();\n}\n\nUtilisez les discriminated unions pour les états complexes :
\n// Mauvais : on ne sait pas ce qu'il y a dans l'objet\ntype Status = 'loading' | 'success' | 'error';\n\ninterface State {\n status: Status;\n data?: Data;\n error?: string;\n}\n\n// Bon : cha