はじめに
AntigravityでReact Native/Expoプロジェクトの開発していると、tsconfig.jsonでパスエイリアス(@/など)を設定したのに、ESLintでエラーが表示されるという問題に遭遇することがあります。
VSCodeの拡張機能によっては問題なく動作する(または)Cursorでは問題なく動作するのに、Antigravityではエラーが出るという不思議な状況でした。この記事では、その原因と解決方法を解説します。
問題の症状
以下のようなインポート文でESLintエラーが発生:
import { LoadingScreen } from "@/components/LoadingScreen";
import { useAuth } from "@/contexts/AuthContext";
エラー内容:
Unable to resolve path to module '@/components/LoadingScreen'
環境
- Expo: ~54.0.23
- React Native: 0.81.5
- TypeScript: ~5.9.2
- ESLint: ^9.0.0
- eslint-config-expo: ~10.0.0
原因
問題の根本原因は、ESLintがTypeScriptのパスマッピングを理解できていないことです。
なぜエディタによって挙動が違うのか?
-
Cursor(VSCode系): TypeScript言語サーバーを使用しており、
tsconfig.jsonの設定だけでパスエイリアスを認識できる - その他のツール: ESLint自体が正しく設定されていないと、パスエイリアスを解決できずエラーとして表示される
つまり、tsconfig.jsonにパスエイリアスを設定しただけでは、ESLintはそれを認識できません。
解決方法
1. 必要なパッケージをインストール
まず、ESLintがTypeScriptのパスエイリアスを解決するために必要なパッケージをインストールします。
npm install --save-dev eslint-plugin-import eslint-import-resolver-typescript
インストールするパッケージの役割:
-
eslint-plugin-import: ESLintでimport/export文を適切に処理するためのプラグイン -
eslint-import-resolver-typescript: TypeScriptのパスマッピング(paths)を解決するためのリゾルバー
2. ESLint設定ファイルを更新
次に、eslint.config.jsを以下のように更新します。
変更前:
// eslint.config.js
const { defineConfig } = require('eslint/config');
const expoConfig = require("eslint-config-expo/flat");
module.exports = defineConfig([
expoConfig,
{
ignores: ["dist/*"],
},
{
settings: {
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: "./tsconfig.json",
},
},
},
},
]);
変更後:
// eslint.config.js
const { defineConfig } = require('eslint/config');
const expoConfig = require("eslint-config-expo/flat");
const importPlugin = require("eslint-plugin-import");
module.exports = defineConfig([
expoConfig,
{
ignores: ["dist/*"],
},
{
plugins: {
import: importPlugin,
},
settings: {
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: "./tsconfig.json",
},
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
},
"import/extensions": [".js", ".jsx", ".ts", ".tsx"],
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"],
},
},
},
]);
設定の説明
plugins
plugins: {
import: importPlugin,
}
-
eslint-plugin-importを明示的にプラグインとして追加
settings["import/resolver"]
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: "./tsconfig.json",
},
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
}
-
typescript:
tsconfig.jsonのパスマッピングを使用してモジュールを解決 - node: Node.jsのモジュール解決アルゴリズムも併用(拡張子を指定)
その他の設定
"import/extensions": [".js", ".jsx", ".ts", ".tsx"],
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"],
}
- TypeScriptファイルの拡張子を認識させる
- TypeScriptパーサーを指定
3. tsconfig.jsonの確認
念のため、tsconfig.jsonにパスエイリアスが正しく設定されているか確認しましょう。
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"paths": {
"@/*": ["./*"]
}
}
}
結果
これで、以下のようなパスエイリアスを使用したインポート文が正常に認識されるようになります。
import { LoadingScreen } from "@/components/LoadingScreen";
import { useAuth } from "@/contexts/AuthContext";
import { hasCompletedWalkthrough } from "@/utils/walkthroughUtils";
ESLintのエラーが消え、快適に開発できるようになります!
まとめ
- TypeScriptのパスエイリアスをESLintで認識させるには、専用のプラグインとリゾルバーが必要
-
eslint-plugin-importとeslint-import-resolver-typescriptをインストール -
eslint.config.jsでプラグインと詳細な設定を追加 - エディタの言語サーバーとESLintは別物なので、それぞれ適切な設定が必要
参考リンク
おわりに
この原因究明のためにclaude codeの時限トークンを一気に消費してしまいました。
今後のAIの発展のためにここに記す(何様)