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
になっていないかと提案をしてくれましたが、いずれも間違っていなかったので、答えに辿り着くまでに少々時間がかかりました。