⚙️

VSCode上で複数のtsconfigを適用させるプラクティス

2023/07/28に公開

VSCodeではTypeScriptファイルの配置されている階層からルートディレクトリまで辿って、見つかったtsconfig.jsonをそのファイルのパースに使用します。(ref

使用されているtsconfig.jsonはステータスバーから確認出来ます。

またreferencesで参照されたtsconfigにマッチする場合はそのtsconfigが使用されます。

単一のtsconfig設定で問題なければルート階層にtsconfig.jsonを配置すれば問題ありませんが、ファイルによって適用させたいtsconfigを分岐したい場合は、

  1. サブディレクトリにtsconfig.jsonを置く
  2. include/excludeでフィルタしたtsconfigを作成し、references・compositeで合成する

のいずれかで実現出来ます。

以下アプリケーションコードとテストコードで別のtsconfigを適用させたいケースで例示します。
手元で確認したい場合はこちらのリポジトリをクローン・参照してください。
https://github.com/bisquit/tsconfig-playground

サブディレクトリにtsconfig.jsonを置く

サブディレクトリにtsconfig.jsonを置けば、そのディレクトリ内のファイルはそのtsconfig.jsonを参照します。

src/
  index.ts

test/
  index.test.ts
  tsconfig.json // テストコード用

tsconfig.json // アプリケーションコード用
tsconfig.json(アプリケーションコード用)
{
  "compilerOptions": {
    ...
  },
  "include": ["src/**/*"]
}
test/tsconfig.json(テストコード用)
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    ...
  },
  "include": ["./**/*"]
}

ここではテストコード用tsconfig.jsonがアプリケーションコード用tsconfig.jsonをextendsしていますが、これは参照の条件には関係ないので単純に設定を流用したいかどうかで構いません。
ただしextendsした場合はアプリケーションコード用のincludeが適用されてテストコードが含まれないため、**/*で上書きしています。

この状態でテストコード(test/index.test.ts)を開くとテストコード用のtsconfig.jsonが適用されていることが確認出来ます。

またこのルールを考慮すると必ずしもルート階層にtsconfig.jsonを置かずに、ディレクトリ毎に置くことも可能です。

src/
  index.ts
  tsconfig.json // アプリケーションコード用

test/
  index.test.ts
  tsconfig.json // テストコード用

include/excludeでフィルタしたtsconfigを作成し、references・compositeで合成する

アプリケーションコード用のtsconfig.jsonとテストコード用のtsconfig.test.jsonを作成しreferencesで参照します。

こちらの方法は前述のように対象コードがディレクトリで分割されていない構成でも可能です。

src/
  index.ts
  index.test.ts

tsconfig.json // アプリケーションコード用
tsconfig.test.json // テストコード用
tsconfig.json(アプリケーションコード用)
{
  "compilerOptions": {
    ...
  },
  "include": ["src/**/*"],
  "exclude": ["src/**/*.test.ts"],
  "references": [
    {
      "path": "tsconfig.test.json"
    }
  ]
}
tsconfig.test.json(テストコード用)
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    ...
    "composite": true
  },
  "include": ["src/**/*.test.ts"],
  "exclude": []
}

こちらもテストコード用tsconfig.test.jsonがアプリケーションコード用tsconfig.jsonをextendsしているため、includeとexcludeを上書きしています。

この例ではルートのtsconfig.jsonをアプリケーション用にしていますが、ファイル名から意図を明確にしたい場合はたとえばtsconfig.app.jsonにしてルートのtsconfig.jsonでreferencesしても問題ありません。(Solution Styleと呼ばれます)

tsconfig.json
{
  "files": [],
  "references": [
    {
      "path": "tsconfig.app.json"
    },
    {
      "path": "tsconfig.test.json"
    }
  ]
}
tsconfig.app.json(アプリケーションコード用)
{
  "compilerOptions": {
    ...
  },
  "include": ["src/**/*"],
  "exclude": ["src/**/*.test.ts"]
}
tsconfig.test.json(テストコード用)
{
  "compilerOptions": {
    ...
  },
  "include": ["src/**/*.test.ts"]
}

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files
https://www.mizdra.net/entry/2022/03/24/093000

IDE用とコンパイル用で分ける

ここまではコードの種類によってtsconfigを分けていましたが、他のケースとしてコンパイル対象をフィルタするためにtsconfigを分けたい場面があります。
(たとえばコンパイル対象からテストコードやstorybookのコードを除外したい等)

その場合は前述のパターンでtsconfigを分けた上で、コンパイル用のtsconfig.build.jsonのようなtsconfigを作ります。

src/
  AppButton.tsx
  AppButton.stories.tsx
  AppButton.test.ts

tsconfig.json       // IDE用(referencesでappとtestを含める)
tsconfig.app.json   // アプリケーション用
tsconfig.test.json  // テスト用
tsconfig.build.json // コンパイル用
tsconfig.build.json
{
  "extends": "./tsconfig.app.json",
  "exclude": ["src/**/*.stories.tsx", "src/**/*.test.ts"]
}
tsc -p tsconfig.build.json

まとめ

複数のtsconfigを適用させる場合は、

  • サブディレクトリにtsconfig.jsonを置く
  • include/excludeでフィルタしたtsconfigを作成し、references・compositeで合成する
  • コンパイル用に分けたい場合はさらにコンパイル用のtsconfig.build.jsonを作成する

Discussion