Repository: TypeScript
Issue: Portability error issued when reachable source file is redirected to an unreachable target
Labels: Bug,Domain: Declaration Emit

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->

resolution, symlinks, references, incorrect dependency

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->

I have tested typescript@4.0.2 and typescript@next and both experience this.

- This is the behavior in every version I tried, and I reviewed the FAQ for entries about module resolution

### ⏯ Playground Link

I can't give a playground link as this issue revolves around dependencies

### 💻 Code

I have created a repo demonstrating this here: https://github.com/jordanmbell/ts-resolution-issue

It is difficult to demonstrate this issue in a few lines because it revolves around dependencies, but the errors are reported here.

```
import { BAD_TYPE, OTHER_BAD } from "fake-dep";

export const bad = (arg: BAD_TYPE) => {
  return arg;
};

const other_bad: OTHER_BAD = 1;

console.log(bad);
```
## The problem

### Screenshot of the issue

Here we see that there are two errors reported, one saying:
`The inferred type of 'bad' cannot be named without a reference to 'subpackage-a/node_modules/fake-dep/dist/BadType'. This is likely not portable. A type annotation is necessary.ts(2742)
`
and one saying:
`Type 'number' is not assignable to type 'string'.ts(2322)`

However from the screenshots of the dependency inside that package, it would seem this error should not be a problem, as `OTHER_BAD` has type `number`, and there is a direct reference to `BAD_TYPE`. Strangely though, typescript tells us it is actually using the version of `fake-dep` from a completely different subpackage.


![image](https://user-images.githubusercontent.com/50465383/169198524-7c565726-ff18-4fcd-8a4f-6c22dcf361f9.png)

![image](https://user-images.githubusercontent.com/50465383/169204970-ebb3ad9f-1be3-4afa-8579-84a9e4fc5a55.png)

I believe the problem is that typescript is caching dependencies when it first finds them, and uses the same located version of that dependency when it finds it used later, even if that dependency should not be reachable. This repo demonstrates that inside of `subpackage-d`, which has an index file that imports `fake-dep` and creates some variables. `tsc` reports a problem though, that `other_bad` should be a `string`, and that `bad cannot be named without a reference to 'subpackage-a/node_modules/fake-dep/dist/BadType'`. These errors occur because rather than `subpackage-d` using the version of `fake-dep` found inside its `node_modules`, it uses the version found inside of `subpackage-a`'s `node_modules`.

Through testing it seems that `subpackage-a`'s version is being used because `subpackage-d` references and imports `subpackage-c`, and following the chain of references and imports eventually reaches the import for `fake-dep` inside of `subpackage-a`. This seems to then be cached, and when TypeScript finally gets back to `subpackage-d`'s index file, it uses the cached version for `fake-dep`, rather than looking for a version from the current folder. I believe this to be a caching issue because if the file inside `subpackage-d` that imports `subpackage-c` (`indew.js`) is alphabetically located after the index file, such as renaming it to `indey.js`, the issue no longer exists.

### Why this is a problem

For most purposes, the caching of a dependency like `fake-dep` would not matter. In fact one of the two issues, the one with `other-bad` saying it should be a `string` is not an issue that would normally come up, it only occurs here because I have manually edited the files inside `node_modules` to be different even though `subpackage-d` and `subpackage-a` have dependencies on the same version, and thus the files should all be the same.

The second issue with `bad cannot be named without a reference to 'subpackage-a/node_modules/fake-dep/dist/BadType'` is a real problem though. Because TypeScript has cached the initial location of where `fake-dep` was resolved to inside `subpackage-a`, it believes that types can not be inferred without a reference to that location, as it does not see that `subpackage-d` has any direct reference to `subpackage-a/node_modules/fake-dep/dist/BadType`. This is likely the reason for many of the `ts(2742)` issues people have had in the past, as it is erroneous and very confusing to track down why an error is being reported.

### What should happen instead

Rather then directly using the cached version of a dependency, TypeScript should use use the same computed exported types but change the location where it has marked the types as being resolved from. This would keep the benefit of not recalculating types for the same package, but would fix the error where it thinks types are being used without a reference.