TypeScriptと使ってプロジェクトにおいてUIコンポーネントを作成して、いざ活用して別のコンポーネントを作成しようと際に、index.tsxではなくindex.tsを参照してしまう問題に直面しました。その当時のディレクトリ設計やtsconfig.jsonと合わせて説明しようと思います。
ディレクトリ設計
ざっくりですが、以下のようなディレクトリ設計を組んでました。
apps/
├── routes/
│ └── _index.tsx
└── ui/
└── button/
├── index.ts // ユーティリティ関数等を定義
└── index.tsx // Buttonコンポーネントを定義
tsconfig.json
{
"include": [
"**/*",
"**/.server/**/*",
"**/.client/**/*",
".react-router/types/**/*"
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["node", "vite/client"],
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"rootDirs": [".", "./.react-router/types"],
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true
}
}
問題
routes/_index.tsxファイル内でimport { Button } from '~/ui/button'と記載した際、TS2305: Module "~/ui/button/index" has no exported member Buttonというエラーが発生しました。
原因
TypeScriptにおいてディレクトリを指定した場合、自動的にindex.tsを探すモジュール解決ルールが存在します。
そのため、同階層にindex.tsとindex.tsxがそれぞれ存在すると、index.tsが優先され、index.tsxは無視されてしまいます。
解決方法
以下どちらかが解決方法になります。
-
index.tsのファイル名を変更する -
buttonディレクトリにサブディレクトリを作成して、そっちでindex.tsを管理する
今回は2の方を採用し、ディレクトリ設計を以下のように変更しました。
apps/
├── routes/
│ └── _index.tsx
└── ui/
└── button/
├── _logics/
│ └── index.ts
└── index.tsx
まとめ
ChatGPTに相談したところ、tsconfig.json内のinclude設定やresolveJsonModuleがfalseになっていないかと提案をしてくれましたが、いずれも間違っていなかったので、答えに辿り着くまでに少々時間がかかりました。