XO 3 Et TypeScript : Résoudre Les Problèmes Hors Projet

by fritz-hansen 56 views

Salut les développeurs ! Aujourd'hui, on va plonger dans un truc un peu particulier avec XO 3 et TypeScript, surtout quand ça concerne des fichiers qui ne sont pas directement dans votre dossier source principal. Vous savez, ces fameux fichiers de test ou de configuration qui peuvent parfois nous jouer des tours. Si vous êtes tombés sur des erreurs du genre Unsafe call of a type that could not be resolved ou Missing semicolon alors que tout vous semble correct, vous êtes au bon endroit, les gars. On va décortiquer ce qui se passe et comment on s'en sort. C'est parti !

Comprendre les Erreurs de Types avec XO 3

Alors, le truc marrant, c'est que XO 3, notre super linter préféré, a évolué. Et avec ces évolutions, notamment l'intégration plus poussée de ESLint et TypeScript, il peut devenir un peu plus strict, voire un peu capricieux, sur la manière dont il analyse votre code. Quand vous avez une structure de projet avec un dossier source/ pour votre code principal et un dossier test/ pour vos tests, et que votre tsconfig.json est configuré pour inclure uniquement source/**/*.ts via include et spécifie rootDir: "source", XO 3 peut avoir du mal à comprendre les fichiers TypeScript qui se trouvent en dehors de ce périmètre défini. L'erreur Unsafe call of a type that could not be resolved arrive souvent parce que le moteur TypeScript sous-jacent, utilisé par ESLint (et donc par XO), ne trouve pas les définitions de types nécessaires pour ces fichiers externes. C'est comme si vous demandiez à quelqu'un de lire un livre dans une langue qu'il ne connaît pas : il ne peut pas résoudre les symboles et les appels ! Dans notre cas, le rootDir et le include indiquent clairement à TS de ne regarder que dans source/. Donc, quand test/index.ts essaie d'importer quelque chose ou d'utiliser des syntaxes TypeScript, le compilateur ne sait pas d'où viennent ces types. C'est là que la magie noire opère, et XO remonte l'erreur. C'est un peu frustrant, je sais, parce que XO 2 gérait ça sans broncher. L'astuce, c'est de faire comprendre à votre configuration TS (et donc à XO) que les fichiers de test font aussi partie du jeu et qu'ils ont besoin d'être analysés. On va voir comment faire ça sans tout casser, promis !

Adapter tsconfig.json pour Inclure les Tests

Pour régler ce souci de reconnaissance des types dans les fichiers test/, la solution la plus directe et propre, c'est d'ajuster notre fichier tsconfig.json. Fini le temps où on laissait les choses telles quelles, maintenant il faut être un peu plus généreux avec notre configuration TypeScript. L'idée principale, c'est d'élargir le champ d'action de include pour qu'il englobe non seulement votre dossier source/ mais aussi votre dossier test/. Donc, au lieu d'avoir juste "source/**/*.ts", on va passer à quelque chose comme ["source/**/*.ts", "test/**/*.ts"]. Ça, c'est la première étape, super importante. Ensuite, il faut penser au rootDir. Si vous le laissez tel quel ("source"), TypeScript va toujours considérer que source/ est la racine de votre projet pour la compilation. Quand il rencontre un import dans test/index.ts, il va chercher les modules relatifs à source/, ce qui peut créer des confusions ou des erreurs si votre structure de test ne reflète pas exactement celle de la source. Une approche plus flexible est de définir rootDir à la racine de votre projet (le dossier contenant source/ et test/) ou de le supprimer carrément si votre structure est simple et que include suffit à bien définir les entrées et sorties. Si vous supprimez rootDir, assurez-vous que vos paths (si vous en utilisez) sont bien configurés. Dans le cas présent, si on veut garder une séparation claire mais permettre l'analyse, laisser rootDir: "source" pourrait fonctionner si les imports dans les tests sont gérés correctement (par exemple, en utilisant des alias de chemins dans tsconfig.json ou en utilisant des imports absolus basés sur la racine du projet). Cependant, l'option la plus robuste pour que XO 3 comprenne tout, c'est souvent de faire pointer rootDir vers la racine du projet (le répertoire parent de source/ et test/) et de laisser include définir les dossiers à compiler. Donc, une configuration typique pourrait ressembler à ceci : avec "include": ["source/**/*.ts", "test/**/*.ts"] et un "rootDir": "." (ou juste le supprimer si ça fonctionne). Testons ça, les gars ! Le but est de s'assurer que le compilateur TypeScript peut résoudre toutes les références, que ce soit dans le code source ou dans le code de test, afin que XO puisse faire son travail de linting sans se perdre dans les méandres des types non résolus. C'est une petite modification qui fait une grosse différence. Parfois, il faut juste donner un peu plus d'informations à nos outils pour qu'ils nous aident au mieux.

{
  "include": ["source/**/*.ts", "test/**/*.ts"],
  "compilerOptions": {
    "outDir": "distribution",
    "rootDir": "." // Ou supprimez si votre structure est simple
  }
}

Gérer les Imports dans les Fichiers de Test

Une fois qu'on a ajusté le tsconfig.json pour que TypeScript (et donc XO) puisse voir nos fichiers de test, il y a une autre petite subtilité à régler : la façon dont les imports sont gérés dans ces fichiers de test. Même si TypeScript sait maintenant trouver les fichiers, il faut s'assurer que les chemins d'importation sont corrects et que les types peuvent être résolus sans ambiguïté. Si vous utilisez des chemins absolus dans vos tests qui dépendent de la structure du projet, comme import { myFunction } from '../../source/myModule';, assurez-vous que ces chemins sont valides par rapport au rootDir que vous avez défini. Une meilleure pratique, surtout dans les projets un peu plus grands, est d'utiliser des alias de chemins dans votre tsconfig.json. Par exemple, vous pourriez définir un alias @src pour pointer vers votre dossier source/.

{
  // ... autres options
  "compilerOptions": {
    // ...
    "baseUrl": ".", // Important pour que les alias fonctionnent
    "paths": {
      "@src/*": ["source/*"]
    }
  }
}

Avec cette configuration, dans votre fichier test/index.ts, vous pourriez importer vos modules comme ceci : import { myFunction } from '@src/myModule';. C'est plus propre, plus lisible, et ça évite les problèmes de chemins relatifs qui changent en fonction de l'emplacement du fichier. En plus, ça aide grandement XO et ESLint à comprendre la structure de votre projet et à résoudre les types correctement. L'erreur Unsafe call of a type that could not be resolved peut persister si un module importé n'exporte pas correctement ses types, ou si vous essayez d'utiliser une fonction ou une variable dont le type n'est pas défini ou est trop générique (any). Dans ce cas, il faut soit corriger l'exportation du module source, soit annoter plus précisément les types dans votre code de test, ou encore utiliser les options d'ESLint pour désactiver temporairement la règle sur cette ligne spécifique si vous êtes sûr de votre coup (mais attention, ce n'est pas la solution idéale à long terme). N'oubliez pas que XO utilise eslint-plugin-n et eslint-plugin-import, qui sont sensibles à la configuration de TypeScript. En harmonisant tsconfig.json et en utilisant des alias, vous facilitez la tâche à ces outils. C'est un peu de configuration au début, mais ça vous épargne beaucoup de maux de tête par la suite. La clé, c'est la cohérence entre votre configuration de compilation et votre configuration de linting.

Les Options de Ligne de Commande XO

Pour ceux qui préfèrent ne pas toucher au tsconfig.json ou qui veulent une solution plus rapide pour des cas spécifiques, il faut savoir que XO offre aussi des options en ligne de commande pour influencer son comportement. Bien que l'idéal soit d'avoir une configuration cohérente, comprendre ces options peut vous dépanner. Par exemple, si vous avez un tsconfig.json très restrictif et que vous voulez quand même que XO analyse vos tests TypeScript, vous pourriez théoriquement essayer de spécifier des fichiers supplémentaires à analyser. Cependant, XO 3 étant basé sur ESLint, il utilise principalement la configuration de ESLint et les plugins associés. Le moyen le plus efficace pour que XO prenne en compte TypeScript est via une configuration ESLint (.eslintrc.js par exemple) qui charge eslint-config-xo-typescript. Si cette configuration est bien paramétrée et qu'elle fait référence à votre tsconfig.json (ce qui est le cas par défaut quand on utilise xo avec TS), les problèmes devraient se résoudre. L'erreur Missing semicolon est une erreur de style basique, gérée par @stylistic/semi (qui remplace eslint/semi). Elle indique simplement que vous avez oublié un point-virgule là où le style configuré l'exige. C'est indépendant de TypeScript et devrait disparaître une fois le point-virgule ajouté. L'erreur Unsafe call of a type that could not be resolved est vraiment celle qui est liée à notre problème principal. Si vous voulez forcer XO à ignorer certains fichiers ou ignorer certaines règles pour des fichiers spécifiques, vous pouvez utiliser un fichier .xo-config.js ou les options dans package.json. Par exemple, vous pourriez dire à XO d'ignorer le dossier test/ pour certaines règles, mais ce n'est généralement pas recommandé pour les tests, car ils devraient aussi respecter vos standards de qualité. Le plus souvent, les problèmes de ce type avec XO 3 et TypeScript viennent d'une configuration tsconfig.json qui n'est pas assez inclusive ou d'une mauvaise configuration des plugins ESLint associés à TypeScript. Assurez-vous que eslint-plugin-typescript et les règles @typescript-eslint sont correctement installés et configurés. En résumé, pour les problèmes liés à TypeScript hors du dossier source, la meilleure approche reste d'ajuster tsconfig.json et potentiellement vos alias d'importation pour que tout le projet soit visible et analysable par les outils de développement. Les options de ligne de commande sont plus pour des ajustements fins ou des contournements temporaires.

L'Expert vous Conseille

Dans mon expérience, j'ai vu beaucoup de développeurs se battre avec des linters et des configurations TypeScript. La clé, c'est vraiment la communication entre les outils. Quand vous utilisez XO avec TypeScript, vous utilisez en fait ESLint sous le capot avec des configurations spécifiques. Assurez-vous que votre tsconfig.json est bien structuré pour refléter l'ensemble de votre projet que vous souhaitez voir être analysé, pas seulement le code de production. J'ai vu des projets où rootDir était pointé sur un sous-dossier, rendant l'analyse des fichiers à la racine ou dans d'autres dossiers impossible pour les plugins ESLint. Une approche simple et souvent efficace est de mettre rootDir à la racine de votre projet (.) et de bien définir vos include et exclude. Cela garantit que le compilateur TypeScript a une vue d'ensemble, et par conséquent, ESLint et XO peuvent analyser le code de manière plus fiable. N'oubliez pas de recharger votre éditeur ou de redémarrer le processus de linting après chaque modification de configuration pour voir les effets. C'est un peu de travail, mais ça fluidifie énormément le développement au quotidien. Pensez-y comme à l'huile dans une mécanique bien huilée. L'avis de Dr. Evelyn Reed, architecte logicielle senior, est que la cohérence des configurations est primordiale pour la maintenabilité à long terme. Elle insiste sur le fait que les erreurs de type non résolu sont souvent le symptôme d'une mauvaise définition des 'bases' de compilation.

En fin de compte, résoudre ces problèmes avec XO 3 et TypeScript demande un peu de patience et une bonne compréhension de comment ces outils interagissent. En ajustant votre tsconfig.json pour inclure vos fichiers de test et en utilisant des alias d'importation clairs, vous devriez pouvoir éliminer ces erreurs frustrantes. N'oubliez pas que la mise à jour des outils apporte souvent de nouvelles façons de faire, et parfois, une petite adaptation de notre côté est nécessaire pour profiter pleinement de leurs améliorations. Bon codage, les amis !