Comment les alias TypeScript vous font gagner des heures
\nAvez-vous déjà écrit quelque chose comme import UserService from '../../../../../services/UserService' ? Si oui, vous connaissez cette douleur. Les yeux qui se croisent, le refactoring qui devient un cauchemar, et tout déplacement de fichier qui casse la chaîne d'imports. Heureusement, TypeScript (et son fichier de configuration tsconfig.json) propose une solution élégante : les paths.
Mais voici la question : comment cela fonctionne-t-il sous le capot ? Pourquoi, après avoir défini l'alias "@/*", pouvez-vous écrire import { UserService } from '@/services/UserService' ? Et surtout, pourquoi cela ne fonctionne-t-il parfois pas sans configuration supplémentaire du bundler (webpack, Vite, Rollup) ?
Dans cet article, nous ne nous contenterons pas de vous montrer comment configurer les paths dans tsconfig.json. Nous allons explorer le mécanisme interne, comprendre le path mapping, découvrir comment TypeScript résout les modules, et apprendre à éviter les erreurs courantes.
\n\nQue sont les paths dans tsconfig.json ?
\nPaths est une section dans tsconfig.json qui permet de définir des correspondances personnalisées (mapping) entre des alias d'import et les chemins réels vers les fichiers. En termes simples, vous dites à TypeScript : « Quand tu rencontres un import commençant par @utils/, cherche en réalité le fichier dans le dossier src/utils/ ».
Voici à quoi cela ressemble dans le code :
\n\n// tsconfig.json\n{\n "compilerOptions": {\n "baseUrl": ".",\n "paths": {\n "@/*": ["src/*"],\n "@utils/*": ["src/utils/*"],\n "@components/*": ["src/components/*"]\n }\n }\n}\n\n\nDésormais, au lieu d'horribles chemins relatifs, vous écrivez :
\n// Avant (cauchemar)\nimport { formatDate } from '../../../../utils/dateHelpers';\n\n// Après (beauté)\nimport { formatDate } from '@utils/dateHelpers';\n\n\nAvouez que la différence est colossale. Mais comment TypeScript sait-il où aller ?
\n\nComment fonctionne la résolution des modules sous le capot
\nPour comprendre le path mapping dans TypeScript, il faut maîtriser le mécanisme de base de la resolution (résolution des modules). Lorsque TypeScript compile votre code, il utilise une stratégie similaire à celle de Node.js, mais avec des fonctionnalités supplémentaires.
\nLe processus se déroule ainsi :
\n- \n
- Vérification du chemin absolu (commence par
/) — si c'est le cas, recherche à partir de la racine du système de fichiers. \n - Vérification du chemin relatif (commence par
./ou../) — résout par rapport au fichier actuel. \n - Vérification d'un alias défini dans paths — si l'import commence par un préfixe défini dans
paths, TypeScript le remplace par le chemin correspondant dans le mapping. \n - Recherche dans node_modules — si rien ne correspond, le module est recherché comme un package npm. \n
Point crucial : TypeScript ne modifie pas les chemins physiques dans le JavaScript compilé. Il vérifie simplement les types et génère des erreurs si le fichier est introuvable. Le remplacement des alias par les chemins réels au moment de l'exécution est la tâche du bundler (webpack, Vite, tsc-alias).
\n\nPourquoi les paths ne fonctionnent-ils pas « prêts à l'emploi » ?
\nVoici la question la plus fréquente sur Stack Overflow : « J'ai configuré les paths, mais au lancement de l'application, j'obtiens l'erreur "Cannot find module" ». La raison est simple : TypeScript est un transpilateur, pas un bundler.
\nLorsque vous exécutez tsc, il génère des fichiers JS, mais laisse les alias intacts. Par exemple, import { foo } from '@utils/bar' reste tel quel dans le JS. Node.js (ou le navigateur) n'a aucune idée de ce qu'est @utils et génère une erreur.
Pour résoudre ce problème, vous devez utiliser l'une des solutions suivantes :
\n- \n
- tsc-alias — un utilitaire qui, après la compilation, remplace les alias par les chemins réels. \n
- module-alias — un package npm pour enregistrer les alias dans Node.js. \n