<h2 dir="auto">Problems</h2>
<p dir="auto"><code class="notranslate">/// &lt;reference path="..." /&gt;</code> comments (hereafter "reference directives") currently serve<br>
multiple purposes:</p>
<ul dir="auto">
<li>Including another definition file containing global declarations</li>
<li>Including another definition file containing ambient module declarations</li>
<li>Including another implementation file</li>
</ul>
<p dir="auto">The current mechanism has some common shortcomings:</p>
<ul dir="auto">
<li>Relative paths to a common typings folder can be come unwieldy</li>
<li>There's no mechanism to "override" a reference path</li>
<li>Reference directives only ever look in one place to find a file.</li>
</ul>
<p dir="auto">This has resulted in multiple issue reports of people trying to address this:</p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="119972662" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/5893" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/5893/hovercard" href="https://github.com/microsoft/TypeScript/issues/5893">#5893</a> Multiple source roots - or something like classpath, like python_path, like include_path</li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="104604609" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4615" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4615/hovercard" href="https://github.com/microsoft/TypeScript/issues/4615">#4615</a> Support environment variables in reference paths</li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="126668998" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/6482" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/6482/hovercard" href="https://github.com/microsoft/TypeScript/issues/6482">#6482</a> Support a 'declarationPath' option</li>
</ul>
<h2 dir="auto">New Use Case in Bundled Type Acquisition</h2>
<p dir="auto">An important scenario we need to address is the case where multiple typings<br>
files need to refer to the same <em>global</em> set of types or namespaces. If these<br>
libraries refer to multiple versions of the same global types, we have no<br>
existing mechanism for resolving the conflict</p>
<h2 dir="auto">Solution: Library include directive</h2>
<h3 dir="auto">Syntax</h3>
<p dir="auto">The proposed syntax (🚲 🏠 of course) would look like this</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/// &lt;reference library=&quot;jquery/jquery.d.ts&quot; /&gt;"><pre class="notranslate"><span class="pl-c">/// &lt;reference library="jquery/jquery.d.ts" /&gt;</span></pre></div>
<h3 dir="auto">Behavior</h3>
<p dir="auto">This syntax means that the compiler should include the <em>first</em> file found<br>
when searching the following paths, where relative paths are resolved relative<br>
to the project root (either the location of <code class="notranslate">tsconfig.json</code>, or the common<br>
root of all input files):</p>
<ul dir="auto">
<li><code class="notranslate">./typings/jquery/jquery.d.ts</code></li>
<li><code class="notranslate">./node_modules/jquery/jquery.d.ts</code></li>
<li><code class="notranslate">./node_modules/@types/jquery/jquery.d.ts</code></li>
</ul>
<p dir="auto">This search order provides the following desirable behavior:</p>
<ul dir="auto">
<li>When needed, the user can resolve a version conflict by placing a definitive<br>
global version in the local <code class="notranslate">typings</code> folder</li>
<li>A bundled <code class="notranslate">.d.ts</code> file will be found automatically</li>
<li>A <code class="notranslate">types</code> package can fill in for libraries which don't have bundled definitions</li>
</ul>
<p dir="auto">We could conceivably allow for configuration of this search order in <code class="notranslate">tsconfig.json</code> if<br>
needed for complex scenarios.</p>
<h3 dir="auto">UMD</h3>
<p dir="auto">Additionally, when a UMD module definition is found, its global export declaration (if present)<br>
is added to the global scope.</p>
<h2 dir="auto">All-up World</h2>
<p dir="auto">Along with the rest of the typings acquisition story, we can now have a very coherent way to<br>
explain how file references should be managed in TypeScript programs:</p>
<ul dir="auto">
<li>Modules which are part of your program are always imported using <code class="notranslate">import</code></li>
<li>Modules which have definition files are always imported using <code class="notranslate">import</code>, and those <code class="notranslate">import</code>s should resolve to proper modules</li>
<li>Global definitions should always be located via <code class="notranslate">/// &lt;reference library = ...</code> directives</li>
<li>File ordering for concatenated output is managed with <code class="notranslate">/// &lt;reference path = ....</code> directives</li>
</ul>
<p dir="auto">Background:</p>
<p dir="auto">The build does a preprocessing step to build the <code class="notranslate">Diagnostics</code> map, which contains items naming tsc error codes and their corresponding human-readable messages.  The generate-diagnostics target runs before the actual compilation step for tsc.  It takes the diagnostic message from a JSON source and mangles it to create a suitable property name for the <code class="notranslate">Diagnostics</code> object.</p>
<p dir="auto">For example, given the 1100 diagnostic ("Invalid use of '{0}' in strict mode."), we create <code class="notranslate">Diagnostic.Invalid_use_of_0_in_strict_mode</code>.</p>
<p dir="auto">Because we're mangling these, processDiagnosticMessages.ts tries to go through some effort to avoid collisions in the generated property names.  See <code class="notranslate">ts.buildUniqueNameMap</code>, <code class="notranslate">ts.NameGenerator.handleCollisions</code>, and others.</p>
<p dir="auto">For example, when dealing with two hypothetical diagnostic messages "Found '{0}'" and "Found 0", we wouldn't want the name-mangling to produce colliding <code class="notranslate">Found_0</code> keys for both messages.</p>
<p dir="auto">Problem:</p>
<p dir="auto">processDiagnosticMessages.ts does not succeed in its goal to properly deal with collisions.</p>
<p dir="auto">Analysis and Cause:</p>
<p dir="auto">During a visual audit of the code, before actually performing any tests against different inputs, I originally fingered the following line as problematic while eyeballing processDiagnosticMessages.ts:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    nameMap[names[i]] = uniqueNames[i];"><pre class="notranslate"><code class="notranslate">    nameMap[names[i]] = uniqueNames[i];
</code></pre></div>
<p dir="auto">This is in the context of having just produced the <code class="notranslate">uniqueNames</code> from the orginal elements of <code class="notranslate">names</code> (where <code class="notranslate">names</code> actually contains elements whose values are the diagnostic messages).  The use of the two arrays are inverted.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    nameMap[uniqueNames[i]] = names[i];"><pre class="notranslate"><code class="notranslate">    nameMap[uniqueNames[i]] = names[i];
</code></pre></div>
<p dir="auto">(Again, <code class="notranslate">names[i]</code> is a bit of a misnomer.  It actually contains the human-readable text of the diagnostic.)</p>
<p dir="auto">However, this does not resolve the problem.  We can process Example Input 1 (adapted from the example above) and it will produce identical <code class="notranslate">Found_0</code> keys both before and after making the change above.  There are actually several other problems in processDiagnosticMessages.ts wrt collision handling.</p>
<p dir="auto">The use of <code class="notranslate">buildUniqueNameMap</code> actually happens before the name-mangling (<code class="notranslate">convertPropertyName</code>) occurs, so the only time we would ever encounter a collision is if the <em>diagnostic messages</em> are exactly the same (rather than their <em>would-be mangled names</em> being the same as in Example Input).  But in fact, it's not even possible for the messages to be the same, because they come from a JSON source keyed off that message, so they're already guaranteed to be unique.  (Side note: add build preconditions to make sure there are no duplicate messages in the source JSON?)</p>
<p dir="auto">There's also a problem with the <code class="notranslate">isFixed</code> parameter in <code class="notranslate">handleCollisions</code>, but I will file a separate issue about that, for various reasons.</p>
<p dir="auto">Example Input:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
    &quot;Found '{0}'.&quot;: {
        &quot;category&quot;: &quot;Error&quot;,
        &quot;code&quot;: 9999
    },
    &quot;Found 0.&quot;: {
        &quot;category&quot;: &quot;Error&quot;,
        &quot;code&quot;: 9998
    }
}"><pre class="notranslate"><code class="notranslate">{
    "Found '{0}'.": {
        "category": "Error",
        "code": 9999
    },
    "Found 0.": {
        "category": "Error",
        "code": 9998
    }
}
</code></pre></div>