title: How can I use the TS Compiler API to find where a variable was defined in another file
body: <p>given:</p>
  
  <pre><code>// foo.ts
  import { bar } from "./bar"
  
  // bar.ts
  export const bar = 3;
  </code></pre>
  
  <p>If I have a <code>ts.Symbol</code> for the <code>bar</code> in "foo.ts", how can I get to the <code>bar</code> in "bar.ts"?</p>
  
  <p>Ideally, TS compiler API would expose a definition-use chain that I can traverse to find the definition. I don't think it does, though.</p>
  
  <p>So now I'm trying to:</p>
  
  <ul>
  <li>use the module specifier "./bar.ts" and the current <code>ts.SourceFile</code> to get a <code>ts.ResolvedModule</code> object representing "bar.ts", which contains the full file path.</li>
  <li>Do <code>ts.SourceFile(fullFilePath)</code> to get a <code>ts.SourceFile</code> for "bar.ts"</li>
  <li>Do <code>checker.getExportsOfModule(symbolForBarDotTs)</code> to get the exports from "bar.ts" and find the one with a matching name.</li>
  </ul>
  
  <p>The tricky part seems to be resolving the module from the module specifier. I don't want to write the logic for module resolution from scratch because the algorithm is complex and depends on the interaction of at least six compiler options. Two parts of the TS Compiler API seemed promising:</p>
  
  <ul>
  <li><code>host.resolveModuleNames</code>, which is unfortunately only available if the host has implemented it, and the default compiler host does not implement it.</li>
  <li>use <code>(program.getSourceFile(pathToFoo) as any).resolvedModules</code>. The <code>resolvedModules</code> property seems to have exactly what I'm looking for, but is not part of the public API.</li>
  </ul>
  
  <p>Is there a better way? I'm hoping to:</p>
  
  <ul>
  <li>stop using non-private API</li>
  <li><p>stop doing so much work that the compiler already knows how to do</p>
  
  <p>"bar.ts"</p></li>
  </ul>
  
  <p>In this case, it is easy to see that "./bar" refers to the adjacent source file on the file system with a matching name, but when someone uses "paths" or "node_modules" or "@types", etc. then module resolution is non-trivial.</p>
  
  <h2>Update</h2>
  
  <p>For the general question of:</p>
  
  <blockquote>
    <p>If I have a <code>ts.Symbol</code> for the <code>bar</code> in "foo.ts", how can I get to the <code>bar</code> in "bar.ts"?</p>
  </blockquote>
  
  <p><a href="https://stackoverflow.com/a/59847032/2482570">@DavidSherret's answer</a> will work most of the time.</p>
  
  <p>However, it doesn't do what I'm looking for in the following case:</p>
  
  <pre><code>// foo.ts
  import { bar } from "./bar"
  
  // bar.ts
  export { bar } from "./baz"
  
  // baz.ts
  export const bar = 3;
  
  </code></pre>
  
  <p>TypeChecker#getAliasedSymbol says that <code>baz</code> in "foo.ts" points to <code>bar</code> in "baz.ts", skipping "bar.ts" entirely. This worn't work for my purposes, because I'm trying to find out, given a set of entrypoints, which parts of .d.ts files are no longer needed, and remove the unneeded parts. In this case it would be a bad idea to remove "bar.ts".</p>