概要
https://www.typescriptlang.org/tsconfig#paths
{
"paths": {
"任意の文字列/*": ["path/to/first/*", "path/to/second/*"]
}
}
import
する際に記載するパスにエイリアスをつけることができます。
このオプションを指定する場合、baseUrlの指定が必須となります。
paths
に指定するパスは、baseUrlに指定したパスからの相対パスになります。
また、任意の文字列 1 つに対して複数のパスを指定することができます。
その場合、配列の先頭のパスから順に存在をチェックし、見つかった段階でモジュールを返します。
詳細
自前の TS ファイルをimport
する際によく起きるのが、相対パスがやたらと長くなる問題です。
(TS に限った話ではなく JS 全般の問題ですが)
特に自身が配置されているディレクトリよりも上の階層のディレクトリのファイルを参照しようとすると、../
が連続し、かなり見にくくなります。
import Hoge from "../../../../../hoge";
こういう感じの。
paths
は、よく使うパスにエイリアス(別名)をつけておくことでこうした見づらいimport
文を見やすくできるオプションです。
例えば React のレポジトリで、 src/components/
配下にコンポーネントを置いていたとすると、色々な場所でこのパスからファイルをimport
することになるでしょう。
その場合は、例えば下記のようにcomponents
というエイリアスをつけます。
{
"baseUrl": "./",
"paths": {
"components/*": ["src/components/*"]
}
}
このpaths
に指定しているオブジェクトのキー側("components"
)がエイリアスで、バリューの配列に入っている文字列("src/components"
)が実際のパスになります。
エイリアスは任意の文字列で良いので、実際のパスと文字列が同じである必要はありません。
ディレクトリにエイリアスをつける際は、双方の末尾に/*
が必要なことに注意してください。
この時、baseUrlの指定が必須となります。
baseUrlは相対パスでimport
する際の基準となるディレクトリを指定するオプションですが、paths
で指定するパスもこのbaseUrlで指定したディレクトリが基準となります。
src/
├── components
│ ├── hoge.tsx
│ └── dir1
│ └── dir2
│ └── dir3
│ └── piyo.tsx
└── index.ts
↑ 例えばこういう階層だった場合、piyo.tsx
からhoge.tsx
を普通にimport
しようとすると
import { TopComponent } from "../../../hoge";
↑ こうなりますが、先ほどpaths
でエイリアスをつけたので、同じimport
文を
import { TopComponent } from "components/hoge";
↑ こう書くことができます。
ただし、コンパイル後にパスの置換が必要
便利なんですが、実際これだけでコンパイルすると、ランタイムエラーになります。
実際先ほどの例のpiyo.tsx
をコンパイルした JS は、以下のように、components/hoge
がそのまま書き出されており、../../../hoge
になっていません。
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
exports.PiyoComponent = void 0;
var react_1 = __importDefault(require("react"));
var hoge_1 = require("components/hoge"); // <- ここ
exports.PiyoComponent = function () { return (react_1["default"].createElement("div", null,
react_1["default"].createElement("div", null, "I'm at src/components/hoge/piyo/fuga/."),
react_1["default"].createElement(hoge_1.HogeComponent, null))); };
この状態だと、実行時に Cannot find module 'components/hoge'
みたいな感じでエラーになります。
これは、TypeScript が実際のコンパイル時にパスの書き換えを行ってくれないからです。
TypeScript の paths はパスを解決してくれないので注意すべし! – 自主的 20%るぅる
こちらの記事でも紹介されていますが、
Module path maps are not resolved in emitted code · Issue #10866 · microsoft/TypeScript
この挙動に関してはここで大激論が交わされているのを確認することができます。
仕方ないので webpack で置換します。
ts-loader
を使った例は上で紹介した方の例を見てみてください。ここでは next.config.js
の中身を置いておきます。
module.exports = {
webpack(config, options) {
// webpack上でも同じパスを指定
config.resolve.alias["components"] = "src/components";
return config;
},
};
webpack の設定のresolve.alias
が、TS の paths と全く同じ意味合いの設定になります。