<p dir="auto"><code class="notranslate">Promise&lt;Derived&gt;</code> is assignable to <code class="notranslate">Promise&lt;Base&gt;</code> (good), but <code class="notranslate">Promise&lt;Base&gt;</code> is also assignable to <code class="notranslate">Promise&lt;Derived&gt;</code> (bad - should require a cast)</p>
<p dir="auto">This weakens type checking, especially since it's so easy to accidentally create <code class="notranslate">Promise&lt;{}&gt;</code> which is assignable to any other <code class="notranslate">Promise</code>:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function f() {
    return new Promise(resolve =&gt; { resolve(1); });
    // oops, this has a return type of Promise&lt;{}&gt;
}
function g(p: Promise&lt;string&gt;) { /* ... */ }

g(f()); // Allowed due to contravariance!"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">f</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">Promise</span><span class="pl-kos">(</span><span class="pl-s1">resolve</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span> <span class="pl-en">resolve</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-c">// oops, this has a return type of Promise&lt;{}&gt;</span>
<span class="pl-kos">}</span>
<span class="pl-k">function</span> <span class="pl-en">g</span><span class="pl-kos">(</span><span class="pl-s1">p</span>: <span class="pl-smi">Promise</span><span class="pl-kos">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-c">/* ... */</span> <span class="pl-kos">}</span>

<span class="pl-en">g</span><span class="pl-kos">(</span><span class="pl-en">f</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// Allowed due to contravariance!</span></pre></div>
<p dir="auto">It's possible to work around this by extending the Promise interface with a dummy property:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Promise&lt;T&gt; { _assignabilityHack: T }"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">Promise</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span> <span class="pl-c1">_assignabilityHack</span>: <span class="pl-smi">T</span> <span class="pl-kos">}</span></pre></div>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var as: ArrayLike&lt;number | string&gt; = &lt;ArrayLike&lt;string&gt;&gt;null;
var an: ArrayLike&lt;number&gt; = &lt;ArrayLike&lt;number | string&gt;&gt;as; // detect incompatibility

var ps: PromiseLike&lt;number | string&gt; = &lt;PromiseLike&lt;string&gt;&gt;null;
var pn: PromiseLike&lt;number&gt; = &lt;PromiseLike&lt;number | string&gt;&gt;ps; // cannot detect"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">as</span>: <span class="pl-smi">ArrayLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">ArrayLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-c1">null</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">an</span>: <span class="pl-smi">ArrayLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">ArrayLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-s1">as</span><span class="pl-kos">;</span> <span class="pl-c">// detect incompatibility</span>

<span class="pl-k">var</span> <span class="pl-s1">ps</span>: <span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-c1">null</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">pn</span>: <span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-s1">ps</span><span class="pl-kos">;</span> <span class="pl-c">// cannot detect</span></pre></div>
<p dir="auto">We must add the following additional definition to detect the incompatibility of <code class="notranslate">PromiseLike</code>, like a <code class="notranslate">ArrayLike</code>.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface PromiseLike&lt;T&gt; {
    _?: T;
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">PromiseLike</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c1">_</span>?: <span class="pl-smi">T</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface PromiseLike&lt;T&gt; {
    _?: T;
}
var ps: PromiseLike&lt;number | string&gt; = &lt;PromiseLike&lt;string&gt;&gt;null;
var pn: PromiseLike&lt;number&gt; = &lt;PromiseLike&lt;number | string&gt;&gt;ps; // detect incompatibility"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">PromiseLike</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c1">_</span>?: <span class="pl-smi">T</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">var</span> <span class="pl-s1">ps</span>: <span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-c1">null</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">pn</span>: <span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-kos">&lt;</span><span class="pl-smi">PromiseLike</span><span class="pl-kos">&lt;</span><span class="pl-smi">number</span> <span class="pl-c1">|</span> <span class="pl-smi">string</span><span class="pl-kos">&gt;</span><span class="pl-kos">&gt;</span><span class="pl-s1">ps</span><span class="pl-kos">;</span> <span class="pl-c">// detect incompatibility</span></pre></div>
<p dir="auto">This behavior is the spec, but this incompleteness is unfavorable.</p>