<p dir="auto">This proposal is based on <code class="notranslate">C#</code> spec for preprocessor directives. <a href="https://msdn.microsoft.com/en-us/library/aa691099(v=vs.71).aspx" rel="nofollow">https://msdn.microsoft.com/en-us/library/aa691099(v=vs.71).aspx</a></p>
<h3 dir="auto">Problem</h3>
<p dir="auto">Some JS applications are used in multiple platforms. I.e. Cordova/Phonegap for mobile platforms, isomorphic applications for server-side and client-side rendered applications. And those platforms are hosting different set of API:s. We use import statements to import and use a host's API. A developer must guard one platform's API from an another.</p>
<p dir="auto">Before ES6 modules one could guard an import using if statements:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if (IOS_PLATFORM) {
   var http = require('./http-ios');
}"><pre class="notranslate"><span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-c1">IOS_PLATFORM</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-k">var</span> <span class="pl-s1">http</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">'./http-ios'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">ES6 modules prohibits conditional imports, because the import statements must be a file-level statement. So we can't do:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if (IOS_PLATFORM) {
   import {something} from './something';
}"><pre class="notranslate"><span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-c1">IOS_PLATFORM</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">something</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'./something'</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<h3 dir="auto">Solution</h3>
<p dir="auto">We can solve the above problem with preprocessor directives. And here is one example of the problem above solved with a preprocessor directives:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#if IOS_PLATFORM
import {http} from './http';
#endif
"><pre class="notranslate">#<span class="pl-k">if</span> <span class="pl-c1">IOS_PLATFORM</span>
<span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">http</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'./http'</span><span class="pl-kos">;</span>
#<span class="pl-s1">endif</span></pre></div>
<p dir="auto">Proposed directives:</p>
<h4 dir="auto">define directive</h4>
<div class="highlight highlight-source-cs notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#define {VARIABLE} [{VALUE}]"><pre class="notranslate">#define <span class="pl-kos">{</span>VARIABLE<span class="pl-kos">}</span> <span class="pl-kos">[</span><span class="pl-kos">{</span>VALUE<span class="pl-kos">}</span><span class="pl-kos">]</span></pre></div>
<p dir="auto">The define directive defines a global flag or global variable. When a value is specified it is regarded as a preprocessor variable.</p>
<h4 dir="auto">flow directives</h4>
<div class="highlight highlight-source-cs notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#if
#elif
#else
#endif"><pre class="notranslate">#<span class="pl-k">if</span>
#elif
#<span class="pl-k">else</span>
#endif</pre></div>
<p dir="auto">It must exist at least one #if and at maximum one #else directive per control-flow statement. A directive must be closed with an #endif directive. You can also nest preprocessor control-flow statements in each other. In addition to hosting TS code, a control-flow statement's body can also host #define and #error directive that defines additional behaviour for the preprocessor.</p>
<p dir="auto">Each control-flow branch is scoped from other sibling branches. So the below example will yield an access undefined error:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#if branch1
var test = &quot;string&quot;;
#elif branch2
test.length; // error
#endif
test.length; // no error"><pre class="notranslate">#<span class="pl-k">if</span> <span class="pl-s1">branch1</span>
<span class="pl-k">var</span> <span class="pl-s1">test</span> <span class="pl-c1">=</span> <span class="pl-s">"string"</span><span class="pl-kos">;</span>
#<span class="pl-s1">elif</span> <span class="pl-s1">branch2</span>
<span class="pl-s1">test</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">;</span> <span class="pl-c">// error</span>
#<span class="pl-s1">endif</span>
<span class="pl-s1">test</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">;</span> <span class="pl-c">// no error</span></pre></div>
<h4 dir="auto">preprocessor operators:</h4>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="==
!=
&amp;&amp;
||"><pre class="notranslate"><span class="pl-c1">=</span><span class="pl-c1">=</span>
<span class="pl-c1">!=</span>
<span class="pl-c1">&amp;&amp;</span>
<span class="pl-c1">||</span></pre></div>
<p dir="auto">These should work as comparison operators in TS and JS along with parens <code class="notranslate">()</code>.</p>
<h4 dir="auto">error directive</h4>
<div class="highlight highlight-source-cs notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#error {MESSAGE}"><pre class="notranslate">#error {MESSAGE}</pre></div>
<p dir="auto">The error directive is to help guiding developers to set right set of flags and values. In some cases two disjoint branches aren't supposed to be joined. An example is given below:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#if IOS_PLATFORM &amp;&amp; ANDROID_PLATFORM
    #error &quot;Cannot set two platform flags&quot;
#endif"><pre class="notranslate"><code class="notranslate">#if IOS_PLATFORM &amp;&amp; ANDROID_PLATFORM
    #error "Cannot set two platform flags"
#endif
</code></pre></div>
<p dir="auto">Or when a preprocessor variable is set to an invalid value:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#if PLATFORM == windows
    #error &quot;Cannot set platform preprocessor variable to windows.&quot;
#endif"><pre class="notranslate"><code class="notranslate">#if PLATFORM == windows
    #error "Cannot set platform preprocessor variable to windows."
#endif
</code></pre></div>
<p dir="auto">On codeplex this was a popular feature request:</p>
<p dir="auto"><a href="https://typescript.codeplex.com/workitem/111" rel="nofollow">https://typescript.codeplex.com/workitem/111</a><br>
<a href="https://typescript.codeplex.com/workitem/1926" rel="nofollow">https://typescript.codeplex.com/workitem/1926</a></p>
<p dir="auto">Personally I think preprocessor directives like #if, #elif, #else #endif with possibility to specify symbol to compiler would be very useful.<br>
And a way to mark function (or ambient function declaration) as Conditional (something like <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute%28v=vs.110%29.aspx" rel="nofollow">ConditionalAattribute</a> in C#) would be great improvement too.<br>
I have lot's of <code class="notranslate">console.log</code> like function calls that decrease performance of my application and ability to easily remove all calls to this function would be great.</p>