<p dir="auto">Given the new <code class="notranslate">this</code> return type and F-bounded polymorphism I was a little surprised that I still could not express a functor interface</p>
<p dir="auto"><strong>Example of Problem</strong></p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface IFunctor&lt;A&gt; {
  /** Maps `A` into `B` */
  map&lt;B&gt;(f: (a: A) =&gt; B): IFunctor&lt;B&gt;;
}

// A class with more than just IFunctor in it.
class Maybe&lt;A&gt; implements IFunctor&lt;A&gt; {
  constructor(init: A) { this.value = init; }
  isEmpty(): boolean { return false; }
  map&lt;B&gt;(f: (a: A) =&gt; B): IFunctor&lt;B&gt; { return new Maybe(f(this.value)); }
}

function toString&lt;F extends IFunctor&lt;any&gt;&gt;(a: F) { 
  return a.map((v: any) =&gt; '' + v); // no way to define that this returns F&lt;string&gt;
}

let a: Maybe&lt;number&gt; = new Maybe(100);
let b: Maybe&lt;string&gt; = toString(a);
// error TS2322: Type 'IFunctor&lt;string&gt;' is not assignable to type 'Maybe&lt;string&gt;'."><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">IFunctor</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-c">/** Maps `A` into `B` */</span>
  <span class="pl-c1">map</span><span class="pl-c1">&lt;</span><span class="pl-smi">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">A</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">B</span><span class="pl-kos">)</span>: <span class="pl-smi">IFunctor</span><span class="pl-kos">&lt;</span><span class="pl-smi">B</span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-c">// A class with more than just IFunctor in it.</span>
<span class="pl-k">class</span> <span class="pl-smi">Maybe</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-c1">&gt;</span> <span class="pl-k">implements</span> <span class="pl-smi">IFunctor</span><span class="pl-kos">&lt;</span><span class="pl-smi">A</span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-s1">init</span>: <span class="pl-smi">A</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">value</span> <span class="pl-c1">=</span> <span class="pl-s1">init</span><span class="pl-kos">;</span> <span class="pl-kos">}</span>
  <span class="pl-en">isEmpty</span><span class="pl-kos">(</span><span class="pl-kos">)</span>: <span class="pl-smi">boolean</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-c1">false</span><span class="pl-kos">;</span> <span class="pl-kos">}</span>
  <span class="pl-en">map</span><span class="pl-c1">&lt;</span><span class="pl-smi">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">A</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">B</span><span class="pl-kos">)</span>: <span class="pl-smi">IFunctor</span><span class="pl-kos">&lt;</span><span class="pl-smi">B</span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">Maybe</span><span class="pl-kos">(</span><span class="pl-en">f</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">value</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-k">function</span> <span class="pl-en">toString</span><span class="pl-c1">&lt;</span><span class="pl-smi">F</span> <span class="pl-k">extends</span> <span class="pl-smi">IFunctor</span><span class="pl-kos">&lt;</span><span class="pl-smi">any</span><span class="pl-kos">&gt;</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">F</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> 
  <span class="pl-k">return</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-en">map</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">v</span>: <span class="pl-smi">any</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s">''</span> <span class="pl-c1">+</span> <span class="pl-s1">v</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// no way to define that this returns F&lt;string&gt;</span>
<span class="pl-kos">}</span>

<span class="pl-k">let</span> <span class="pl-s1">a</span>: <span class="pl-smi">Maybe</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-k">new</span> <span class="pl-smi">Maybe</span><span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> <span class="pl-s1">b</span>: <span class="pl-smi">Maybe</span><span class="pl-kos">&lt;</span><span class="pl-smi">string</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-s1">a</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// error TS2322: Type 'IFunctor&lt;string&gt;' is not assignable to type 'Maybe&lt;string&gt;'.</span></pre></div>
<p dir="auto"><strong>Ideal Solution:</strong><br>
Ideally we should be able to define that F needs to have a generic type, which we can change</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface IFunctor&lt;A, F&lt;A&gt; extends IFunctor&lt;&gt; {
  /** Maps `A` into `B` */
  map&lt;B&gt;(f: (a: A) =&gt; B): F&lt;B&gt;;
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">IFunctor</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-kos">,</span> <span class="pl-smi">F</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-c1">&gt;</span> <span class="pl-k">extends</span> <span class="pl-smi">IFunctor</span><span class="pl-kos">&lt;</span><span class="pl-smi"></span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-c">/** Maps `A` into `B` */</span>
  <span class="pl-c1">map</span><span class="pl-c1">&lt;</span><span class="pl-smi">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">A</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">B</span><span class="pl-kos">)</span>: <span class="pl-smi">F</span><span class="pl-kos">&lt;</span><span class="pl-smi">B</span><span class="pl-kos">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">or we can define the functions generics</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function toString&lt;A, F&lt;A&gt; extends IFunctor&lt;A&gt;&gt;(a: F&lt;A&gt;): F&lt;string&gt; { ... }"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-s1">toString</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-kos">,</span> <span class="pl-smi">F</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-c1">&gt;</span> <span class="pl-k">extends</span> <span class="pl-smi">IFunctor</span><span class="pl-c1">&lt;</span><span class="pl-smi">A</span><span class="pl-c1">&gt;</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-smi">F</span><span class="pl-kos">&lt;</span><span class="pl-smi">A</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span>: <span class="pl-smi">F</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></pre></div>
<p dir="auto">It would be enormously helpful if <code class="notranslate">this</code> recognized type parameters:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="abstract class Functor&lt;a&gt; {
   abstract map&lt;b&gt;(map: (value: a) =&gt; b): this&lt;b&gt;;
}

abstract class Monad&lt;a&gt; extends Functor&lt;a&gt; {
   abstract bind&lt;b&gt;(bind: (value: a) =&gt; this&lt;b&gt;): this&lt;b&gt;;
}"><pre class="notranslate"><span class="pl-k">abstract</span> <span class="pl-k">class</span> <span class="pl-smi">Functor</span><span class="pl-c1">&lt;</span><span class="pl-smi">a</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
   <span class="pl-k">abstract</span> <span class="pl-c1">map</span><span class="pl-c1">&lt;</span><span class="pl-smi">b</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">map</span>: <span class="pl-kos">(</span><span class="pl-s1">value</span>: <span class="pl-smi">a</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">b</span><span class="pl-kos">)</span>: <span class="pl-smi">this</span><span class="pl-c1">&lt;</span><span class="pl-smi">b</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">abstract</span> <span class="pl-k">class</span> <span class="pl-smi">Monad</span><span class="pl-c1">&lt;</span><span class="pl-smi">a</span><span class="pl-c1">&gt;</span> <span class="pl-k">extends</span> <span class="pl-smi">Functor</span><span class="pl-kos">&lt;</span><span class="pl-smi">a</span><span class="pl-kos">&gt;</span> <span class="pl-kos">{</span>
   <span class="pl-k">abstract</span> <span class="pl-c1">bind</span><span class="pl-c1">&lt;</span><span class="pl-smi">b</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">bind</span>: <span class="pl-kos">(</span><span class="pl-s1">value</span>: <span class="pl-smi">a</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">this</span><span class="pl-c1">&lt;</span><span class="pl-smi">b</span><span class="pl-c1">&gt;</span><span class="pl-kos">)</span>: <span class="pl-smi">this</span><span class="pl-c1">&lt;</span><span class="pl-smi">b</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>