microsoft / microsoft/TypeScript

foo.ts is resolved before foo.d.ts even if the latter is in files[]

オープン
#22,208 コメント 10 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Committed Help Wanted Suggestion
主要言語
Go
スター
111k
フォーク
14.4k
平均マージ
1日 19時間
マージ済み PR(30日)
117

説明

Affects at least TS 2.7.2 and 2.6.2. This problem appears when compiling files separately, like we do under Bazel.

Imagine this simple app

src/lib.ts

export const a = 1;

src/main.ts

import {a} from './lib';

Imagine lib.ts was compiled separately, so there already exists
dist/lib.d.ts

export declare const a = 1;

Now, I want to compile main.ts as a separate program. Given src/tsconfig.json

{
  "compilerOptions": {
    "rootDirs": [
      ".",
      "../dist"
    ],
    "outDir": "../dist",
    "declaration": true
  },

  "files": [
    "main.ts",
    // lib was compiled separately
    "../dist/lib.d.ts"
  ]
}

We see that lib.d.ts is already in the program before resolution begins. However the compiler resolves the import statement to the lib.ts file instead, adding it to the program, and tries to emit on top of an input, so the error is

$ ./node_modules/.bin/tsc -p src
error TS5055: Cannot write file '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/dist/lib.d.ts' because it would overwrite input file.

Okay, we didn't want lib.ts in the program, so we should just use --noResolve to prevent that, but it's also broken:

$ ./node_modules/.bin/tsc -p src --noResolve --traceResolution
======== Resolving module './lib' from '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/main.ts'. ========
Module resolution kind is not specified, using 'NodeJs'.
'rootDirs' option is set, using it to resolve relative module name './lib'.
Checking if '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/' is the longest matching prefix for '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib' - 'true'.
Checking if '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/dist/' is the longest matching prefix for '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib' - 'false'.
Longest matching prefix for '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib' is '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/'.
Loading 'lib' from the root dir '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/', candidate location '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib'.
Loading module as file / folder, candidate module location '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib', target file type 'TypeScript'.
File '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib.ts' exist - use it as a name resolution result.
======== Module name './lib' was successfully resolved to '/usr/local/google/home/alexeagle/Projects/repro_ts_resolving_ts/src/lib.ts'. ========
src/main.ts(1,17): error TS2307: Cannot find module './lib'.

So far our workaround at Google is one of:

  • use Bazel sandboxing to make the inputs appear in different places
  • use our own custom compiler which elides any emit to files we don't expect

However under Bazel we sometimes cannot sandbox (eg. on Windows) and cannot use our custom compiler (eg. when we are compiling it)
so we are stuck.

I found that ts.CompilerOptions.suppressOutputPathCheck could be a workaround, but tsc doesn't allow that flag from the command line or tsconfig.json (it's not in optionDeclarations in commandLineParser.ts)

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

src/main.ts、src/lib.ts、dist/lib.d.ts、src/tsconfig.json を使い、--traceResolution と --noResolve を指定して個別コンパイルの例を再現します。まずモジュール解決の動作と commandLineParser.ts を読みます。既存の files[] 宣言が lib.ts より優先され、TS5055 上書きエラーが発生しなければ完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
typescript
領域
compilers
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
38/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。