Programming Field

tsconfig.jsonの各種ディレクトリオプション

TypeScriptの設定ファイル「tsconfig.json」では、baseUrlpaths など、import 文で指定されたモジュールの検索(解決)を行う際のヒントとなる設定が存在します。設定の種類によって役割が微妙に異なっており、ここではそれらの違いについて説明しています。

設定の種類

具体的には、ディレクトリやモジュール解決に関する以下のような設定・概念が存在します。

  1. プロジェクトディレクトリ
  2. outDir
  3. rootDir
  4. declarationDir
  5. baseUrl
  6. paths
  7. rootDirs
  8. typeRoots

このうち outDir, rootDir, declarationDir が出力に関する設定、baseUrl, paths, rootDirs, typeRoots が入力に関する設定となります。

プロジェクトディレクトリ

プロジェクトディレクトリは設定項目には存在せず、以下の条件で設定されます。

  1. tsconfig.json が使用される場合 → そのファイルが存在するディレクトリ
    • コンパイラー処理実行時に設定ファイルが明示的に指定された場合は、そのファイルが存在するディレクトリとなります。
    • コンパイラー処理実行時にディレクトリが明示的に指定された場合は、そのディレクトリとなります。
  2. それ以外の場合 → カレントディレクトリ

プロジェクトディレクトリは様々なディレクトリやファイル関連の設定に使用される基準のディレクトリとなります。そのため、入力ファイルや出力ファイルの場所を考える際はプロジェクトディレクトリの位置、ひいては設定ファイル(tsconfig.json)の配置場所もある程度意識する必要があります。

outDir

この設定項目はコンパイル結果(JSファイル)を生成するディレクトリ(「出力ディレクトリ」)を表します。「outFile」設定が存在する場合は指定することができません。出力されるJSファイルは原則として入力ファイルのディレクトリ構造に従いますが、「rootDir」設定によって制御されます。詳しくは「rootDir」設定をご覧ください。

outDir に指定するディレクトリが相対パス指定の場合(先頭が「/」始まりや「x:/」などではない場合)は、相対パスはプロジェクトディレクトリからのパスとして扱われます。

outDir の指定が無い場合は、出力ファイルは入力ファイルと同じディレクトリに生成されます。入力と出力が同じディレクトリに混ざることになるため、通常は別ディレクトリになるように outDir の指定を行います。

rootDir

「rootDirs」設定とは異なります。

この設定項目は出力ファイルのディレクトリ構造を決定する際にのみ使用されます。具体的には、rootDir で指定されたディレクトリをベースに入力ファイルの相対パスを計算し、その相対パスを出力ディレクトリに適用してファイルを出力します。なお、rootDir はプロジェクトディレクトリを基準としたパスとして扱われます。

  • 例: outDir が「dist」、rootDir が「src」である場合 → ファイル「src/hoge/Hoge.ts」は計算された相対パスが「hoge/Hoge.ts」になるので「dist/hoge/Hoge.js」にコンパイルされます。

※ rootDir に設定されたディレクトリが全ての入力ファイルを含むディレクトリではない場合(計算された相対パスに「..」が含まれるようになる場合)はエラー TS6059 となります。
※ outDir の設定が無い場合は、rootDir 設定は効果を持ちません。

rootDir を指定しなかった場合は、全ての入力ファイルで共通の親ディレクトリを rootDir として扱い、前述のルールにのっとって出力先を決定します。

  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」の2つである場合 → rootDir は「src/main」の扱いとなる
  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」と「src/gen/pork.ts」の3つである場合 → rootDir は「src」の扱いとなる
  • 例: 入力ファイルが「src/main/foo.ts」と「src/main/bar.ts」と「src/gen/pork.ts」と「externals/banana.ts」の4つである場合 → rootDir は「.」(プロジェクトディレクトリと同じ)の扱いとなる

なお、この設定は declarationDir 設定でも同様の形で利用されます。

declarationDir

「declaration」が「true」に設定されている場合に出力する、型定義ファイル(.d.ts)の出力先ディレクトリを指定します。declarationDir の指定が無い場合は outDir と同じ設定が利用されますが、declarationDir の指定がある場合は outDir とは関係なく、declarationDir の設定内容をプロジェクトディレクトリ基準のパスとして出力を行います。また、実際の型定義ファイル出力時は declarationDir のパスに対して rootDir 設定を適用して各ファイルの出力を行います。

  • 例: 入力ファイルが「src/main/foo.ts」、declarationDir が「dist/types」、rootDir が「src/main」である場合 → 型定義ファイルとして「dist/types/foo.d.ts」が作成される

baseUrl

この設定項目はモジュールを参照(importrequire、および <reference /> ディレクティブなどを利用)する際に、モジュール名として「非相対モジュール」を指定した時の検索先基準ディレクトリとして用いられます。モジュール名における「相対モジュール」(relative module)は「./」「../」および「/」で始まるモジュール名を表し、「非相対モジュール」(non-relative module)はそれ以外を表します。baseUrl 設定はこのうち「非相対モジュール」の検索パスとして使用されます。(baseUrl 指定はプロジェクトディレクトリ基準のパスとなります。)

  • 例: baseUrl が「ref/dir」である場合に、「src/pairs.ts」が「pairs/palette」というモジュールを参照する場合 → 「ref/dir/pairs/palette」にあるモジュールを参照しようとする

※ このときの解決方法は設定項目「module」が「classic」か「node」かによって異なります。加えて、「module」が「classic」の場合は親ディレクトリに向かって検索範囲を広げる処理が行われます。詳しくはTypeScript Handbookの「Module Resolution - Module Resolution Strategies」をご覧ください。
※ 「相対モジュール」によるモジュール参照に対しては効果はありません。

なお、この設定項目は paths 設定項目に影響します。

paths

この設定項目は baseUrl 設定項目を基準として、特定の「非相対モジュール」名に対して個別のパスマッピングを行う際に使用します。paths の設定内容は以下のように、「特定の『非相対モジュール名』」をキーとして、「マッピングのパターン」を配列で指定します。

  "baseUrl": "src",
  "path": {
    "fruits/*": [
      "../ref/all-fruits/*"
    ],
    "*": [
      "../node_modules/@types/*",
      "../node_modules/*"
    ]
  }

上記の設定例では、「fruits/」で始まる「非相対モジュール」に対しては「ref/all-fruits/」(baseUrl が「src」なので「src/../ref/all-fruits/」として計算)としてマップされます。

  • 例: 上記設定において「import * as Banana from 'fruits/banana';」がある場合 → 「ref/all-fruits/banana」モジュールを参照しようとする

また上記設定例では、「fruits/」以外の「非相対モジュール」への参照が行われた場合は、「node_modules/@types/」以下、および「node_modules/」以下へマッピングして参照を試みます。

※ 設定項目「module」が「node」である場合は、paths 設定によるモジュール検索でモジュールを見つけられなかった場合に、Node.jsと同様に「node_modules」および「node_modules/@types」の各ディレクトリへの検索も行われます。ただし、これは入力ファイルがあるディレクトリを基準に「node_modules」ディレクトリを検索していくため、上記設定例における「../../node_modules」の指定はこの既定処理に優先してモジュールを検索させるために有用な指定となります。

rootDirs

「rootDir」設定とは異なります。

この設定項目は、import や require 文などで指定するモジュール名が「相対モジュール」(relative module; 「./」「../」および「/」で始まるモジュール名)である場合の基準ディレクトリとして使用されます。rootDirs 設定にはディレクトリ名の配列(各ディレクトリはプロジェクトディレクトリ基準のパス)を指定します。

rootDirs 設定がある場合、指定されたそれぞれのディレクトリはマージされたもの(仮想ディレクトリ)として考えます(重複するファイルがある場合は指定順に見つかったものが優先されます)。入力ファイルが(プロジェクトディレクトリを基準として) rootDirs のいずれかのディレクトリ下に存在する場合に限り、「相対モジュール」によるモジュール参照は rootDirs のディレクトリを基準として参照を試みます。

  • 例: rootDirs が「src/main」「src/gen」である場合に、「src/main/food.ts」が「./egg」モジュールへの参照を行う場合 → 「src/main/egg」を検索し、見つからなければ「src/gen/egg」を検索する
  • 例: rootDirs が「src/main」「src/gen」である場合に、「src/index.ts」が「./main/config」モジュールへの参照を行う場合 → 「src/index.ts」から見た「./main/config」は「src/main/config」になってそのディレクトリ rootDirs に含まれるためこの処理の対象となり、まずは「src/main/config」を検索し、見つからなければ「src/gen/config」を検索する
  • 例: rootDirs が「src/main」「src/gen」である場合に、「src/other/animal.ts」が「./egg」モジュールへの参照を行う場合 → (プロジェクトディレクトリを基準とした)パス「src/other/egg」のディレクトリが rootDirs に一致しないので「src/other/egg」のみを検索する

さらにこの設定は、存在しないディレクトリを含めることが可能です。例えば rootDirs を「src/dev」「src/#env」と設定した場合(「src/#env」は存在しないと仮定)、「src/main.ts」が「import * as Config from './#env/config';」と読み込んだ場合「src/dev/config」モジュールの利用を試みます。

typeRoots

typeRoots 設定はこれまで説明した設定項目と若干異なり、コンパイル時に自動的に型定義ファイル(.d.ts)を持つパッケージを読み込む際の検索パスを指定します。ここに指定されたディレクトリ下にあるパッケージ内の型定義ファイルが自動的に使用されます。また、「<reference types='...' />」ディレクティブでの型定義読み込みの検索パスとしても利用されます。typeRoots 設定に指定するディレクトリはプロジェクトディレクトリを基準としたパスとなります。

※ typeRoots に指定するディレクトリはパッケージの検索パスであるため、指定されたディレクトリには「<subdir>/index.d.ts」のようにサブディレクトリを伴ってファイルを設置するか、package.json のあるディレクトリ(パッケージディレクトリ)を置く必要があります。

なお、自動的に型定義を読み込むかどうかは types 設定で制御されます。types 設定が「[]」(空配列)である場合は、typeRoots 設定にかかわらず自動的な読み込みが行われません(「includes」に含めた場合や「<reference types='...' />」ディレクティブで明示的に指定した場合を除く)。