3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TypeScript: 型定義ファイルの解決がCIでだけ失敗する問題が発生しました

Posted at

TypeScriptのプロジェクトで、なぜかローカルではコンパイルが通るけど、CIではコンパイルがコケる問題が発生しました。

問題が発生した状況

CIでコンパイルしているが、そこでコケる

  • このプロジェクトでは、CIでtscを実行して型チェックを行っています。
  • CIを回したら、「error TS2503: Cannot find namespace 'NodeJS'」というエラーが発生しました。
    • これは、NodeJSという型が見つからないというコンパイルエラー。

ローカルではコンパイルが通る

  • ローカル開発環境でtscするとCIで発生しているようなコンパイルエラーは発生しませんでした。
    • 「僕の環境だと動くんですけど」状態

ローカル開発環境のディレクトリ構成

この問題の原因はローカル開発環境のディレクトリ構成が関わっていました。

ローカル開発環境では、~/projectsにプロジェクトごとにディレクトリを作る構成になっています。projectsディレクトリは、複数のプロジェクトを置くだけのスペースで、これをGitHubにpushしたりはしていません。あくまでプロジェクトを整理するために設けたディレクトリです。

今回問題が起こったプロジェクトは~/projects/myprojです。

~/projects
├── myproj # 問題の起こったプロジェクトのプロジェクトルート
│   ├── .git
│   ├── index.ts # ❶
│   ├── node_modules 
│   │   └── @types # ❷
│   │       └── lodash
│   └── tsconfig.json
├── node_modules
│   └── @types
│       └── node # ❸
├── other_project1 # ┐ 
├── other_project2 # ├ 他のプロジェクトのディレクトリたち(今回は関係ない)
└── other_project3 # ┘ 

index.ts(❶)では、概ね次のようなNodeJS.ProcessEnvの型を参照するコードがあります。

index.ts
type A = NodeJS.ProcessEnv;

myprojが単体で、index.tsが正しくコンパイルされれるためには、~/projects/myproj/node_modules/@types/nodeがあるべきでしたが、インストールされていませんでした(❷)。

代わりに、myprojディレクトリのひとつ上のディレクトリprojectsになぜかnode_modulesがあり、その中に@types/nodeがインストールされていました(❸)。

この~/projects/node_modules/@types/nodeがあるため、myproj@types/nodeが無くても、index.tsは問題なくコンパイルがされていました。

一方で、CIの環境にはプロジェクトルートより上のディレクトリにnode_modulesは存在していないため、@types/nodeが見つけられず、コンパイルエラーになっていました。

TypeScriptのモジュール解決

TypeScriptのモジュール解決は、細かく言うといろいろあるのですが、ざっくりいうとNode.jsのモジュール解決を模倣するモードがあります。

そのモードでは、@types/node型定義ファイルを探す場合、次の順でパスを登っていって探します。

  1. /path/to/projects/myproj/node_modules/@types/node
  2. /path/to/projects/node_modules/@types/node
  3. /path/to/node_modules/@types/node
  4. /path/node_modules/@types/node
  5. /node_modules/@types/node

この順で見つからなければコンパイルエラーになります。今回のCIでコンパイルエラーになったのは、5まで登っても@types/nodeが見つからなかったためです。

myprojにちゃんと@types/nodeをインストールしていれば、ステップ1で型定義ファイルが見つかりコンパイルが通っていたはずです。

今回、ローカルでコンパイルエラーにならなかったのは、ステップ2の@types/nodeが採用されていたためです。

一時的な解決策

一時的な対処は、myproj@types/nodeをインストールするだけです。

根本的な解決策

こういうミスが二度と起きないようにするには、不必要なnode_modulesを上のディレクトリに作らないようにすることです。これは個人的に行える対策です。適当なファイルをnode_modulesという名前で作っておけば、うっかりnpm installyarn installを行っても処理が失敗します。

echo 'ここにはnode_modules作らない' > ~/projects/node_modules

プロジェクト単位ではtypeRootsを明示的に設定したほうが良さそうです。

tsconfig.json
 {
   "compilerOptions": {
     "typeRoots": ["./node_modules/@types"],
   }
 }

これを設定しておくと、型定義ファイルを探すのはプロジェクト配下のnode_modules/@typesだけになり、../node_modules/@types../../node_modules/@types、...といった登って探すといったことが行われなくなります。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?