<p dir="auto">It is now possible for a library to hit every type of target that TypeScript supports (module, namespace, and ES6). Currently, writing a declaration file for a library like this can be very challenging. The default today is something like this:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="declare namespace MyLib {
   export ...
}

declare module 'mylib' {
  export = MyLib;
}"><pre class="notranslate"><span class="pl-k">declare</span> <span class="pl-k">namespace</span> <span class="pl-smi">MyLib</span> <span class="pl-kos">{</span>
   <span class="pl-s1">export</span> ...
<span class="pl-kos">}</span>

<span class="pl-k">declare</span> module <span class="pl-s">'mylib'</span> <span class="pl-kos">{</span>
  <span class="pl-k">export</span> <span class="pl-c1">=</span> <span class="pl-smi">MyLib</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">This has a couple issues:</p>
<ol dir="auto">
<li>If you're using this in the module sense, using this declaration file will result in TypeScript thinking there is a globally available variable <code class="notranslate">MyLib</code> which is not actually true. This can lead to runtime errors. (see <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="57469172" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/2018" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/2018/hovercard" href="https://github.com/microsoft/TypeScript/issues/2018">#2018</a>)</li>
<li>If you're using ES6 import syntax TypeScript will consider this module to be in the CommonJS style and will not allow default imports even though the library <em>actually</em> supports them.</li>
</ol>
<p dir="auto">In the past, regarding item 1, it's been suggested that we split the declarations into two files (one for modules and one for namespaces). This makes sense. I think it also makes sense to extend that concept for ES6 modules. So if you have a library that targets all three, then you will have three mutually exclusive declaration files. Where things then become problematic is with duplicating the declarations in each file (which ideally should not happen). It is impossible to import an ambient module into an ambient namespace. It is possible to use an ambient namespace in an ambient module, but a naive approach to that (as shown in the common case above) violates item 1.</p>
<p dir="auto">Therefore, I propose this guidance to writing these declaration files.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// mylib-common.d.ts

declare namespace __MyLib {
  export ...
}

// mylib-namespace.d.ts

/// &lt;reference path=&quot;mylib-common.d.ts&quot; /&gt;
import MyLib = __MyLib;

// mylib-module.d.ts

/// &lt;reference path=&quot;mylib-common.d.ts&quot; /&gt;
declare module 'mylib' {
  export = __MyLib;
}

// mylib-es6.d.ts

/// &lt;reference path=&quot;mylib-common.d.ts&quot; /&gt;
declare module 'mylib' {
  export * from __MyLib; // this doesn't currently work, see #4336
  export default __MyLib; // if there is a default export
}"><pre class="notranslate"><span class="pl-c">// mylib-common.d.ts</span>

<span class="pl-k">declare</span> <span class="pl-k">namespace</span> <span class="pl-s1">__MyLib</span> <span class="pl-kos">{</span>
  <span class="pl-s1">export</span> ...
<span class="pl-kos">}</span>

<span class="pl-c">// mylib-namespace.d.ts</span>

<span class="pl-c">/// &lt;reference path="mylib-common.d.ts" /&gt;</span>
<span class="pl-k">import</span> <span class="pl-smi">MyLib</span> <span class="pl-c1">=</span> <span class="pl-s1">__MyLib</span><span class="pl-kos">;</span>

<span class="pl-c">// mylib-module.d.ts</span>

<span class="pl-c">/// &lt;reference path="mylib-common.d.ts" /&gt;</span>
<span class="pl-k">declare</span> module <span class="pl-s">'mylib'</span> <span class="pl-kos">{</span>
  <span class="pl-k">export</span> <span class="pl-c1">=</span> <span class="pl-s1">__MyLib</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-c">// mylib-es6.d.ts</span>

<span class="pl-c">/// &lt;reference path="mylib-common.d.ts" /&gt;</span>
<span class="pl-k">declare</span> module <span class="pl-s">'mylib'</span> <span class="pl-kos">{</span>
  <span class="pl-k">export</span> <span class="pl-c1">*</span> <span class="pl-k">from</span> <span class="pl-s1">__MyLib</span><span class="pl-kos">;</span> <span class="pl-c">// this doesn't currently work, see #4336</span>
  <span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-s1">__MyLib</span><span class="pl-kos">;</span> <span class="pl-c">// if there is a default export</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Unfortunately this is currently hypothetical since you cannot re-export namespace declarations from an ES6 declaration.</p>
<p dir="auto">I'm proposing this as a baseline for discussion to solve this issue for good. It's possible I'm going down the wrong track or that there is already a better way to handle these cases. It would also be great if we could get some buy-in from the TypeScript language to solve this, if needed.</p>
<p dir="auto">Some possible ways TypeScript could be improved in this area:</p>
<ol dir="auto">
<li>Fix <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="101317013" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/4336" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/4336/hovercard" href="https://github.com/microsoft/TypeScript/issues/4336">#4336</a></li>
<li>Make it so that <code class="notranslate">__MyLib</code> only exists as a namespace and not as a value, either through convention (prefixed with __) or through additional syntax.</li>
</ol>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/johnnyreilly/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/johnnyreilly">@johnnyreilly</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/vvakame/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/vvakame">@vvakame</a></p>
<p dir="auto">I have an issue where I added a <code class="notranslate">Bower</code> component that distributes angular.d.ts, which I already have included elsewhere in my project.</p>
<p dir="auto">Even though my <code class="notranslate">bower_components</code> directory is excluded from the project, it appears TSC is still compiling this d.ts resulting in duplicate declaration errors.</p>
<p dir="auto">Is this the intended behavior of implicit compilation?</p>