はじめに
Advent Calenderの準備をするべく、Reactアプリケーションの開発を行なっていた時の話です。
baseUrlに指定したsrc直下にconstants.ts
を作成し、
定数を定義してimportすると下記のようなエラーが起きました。
モジュール '"constants"' にエクスポートされたメンバー 'BASE_URL' がありません。
「あれ、baseUrlの設定を間違えたかな? それとも定数をexportし忘れている?」
そう思いtsconfig.json
やconstants.ts
を何度も確認しましたが、
間違っている様子はありません。
不審に思って調べていると、どうやらconstants
という名前が悪さをしていたことがわかりました。
再現方法
1. tsconfigにbaseUrlを設定する
{
"compilerOptions": {
...
"baseUrl": "./src"
},
...
}
2. src/constants.tsを作成し、定数を定義する
src/constants.ts
に定数を定義します。
例えば、API_BASE_URL
を定義するとしましょう。
envファイルなどを追加すると余計な要素が増えるので、今回はベタ書きします。
const API_BASE_URL = "http://localhost:3000"
export {
API_BASE_URL
}
3. 定義した定数を他ページから呼び出す。
定義した、API_BASE_URL
を別のページでimportしてみます。
import { API_BASE_URL } from "constants"
export const Sameple = () => {
...
}
すると、API_BASE_URL
に対して前述したようなエラーが出ます。
モジュール '"constants"' にエクスポートされたメンバー 'API_BASE_URL' がありません。
原因
原因は@types/nodeに"constants"という名前のmoduleが存在するためでした。
つまり、この"constants"モジュールのAPI_BASE_URL
をimportしようとしていたけれど、
そんな定数は存在しないため、importに失敗してしまったというわけです。
解決策
1. 相対パスで指定する
解決策の一つは相対パスで指定することです。
// import { API_BASE_URL } from "constants"
import { API_BASE_URL } from "../../constants"
ただ、深い階層になると、"../"が増えて見通しが悪くなるので、あまりお勧めできません。
2. constants.tsという名前を変更する
constants.ts
という名前であるせいで、"constants"モジュールとコンフリクトするので、
const.ts
などとすれば、importできるようになります。
import { API_BASE_URL } from "const"
3. constants.tsをベースディレクトリに置かない
べースディレクトリより下の階層にconstants.ts
を置くという解決策です。
ページ固有の定数なら、src/pages/sample/constants.ts
としたり、
各ページやコンポーネントで共通のものなら、src/common/constants.ts
としたりすれば
import { API_BASE_URL } from "./constants"
や
import { API_BASE_URL } from "common/constants"
というふうにimportできるので、"constans"モジュールとコンフリクトすることはありません。
おわりに
以上、ベースディレクトリにconstants.ts
という名前の定数ファイルを置くのは避けた方が良い、という話でした。
そもそも、constants/api_config.ts
などのように、
定義した定数の意図がわかるようにファイルを作成すれば良いだけのことかもしれません。
ただ、意外と知らなかった現象なので記事にしてみました。
みなさんは自分のように無駄にtsconfig.json
とconstants.ts
を行ったり来たりする時間を送らないように気をつけてください。