<p dir="auto">Say I have an interface</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="interface Applicative&lt;T&gt; {}"><pre class="notranslate"><code class="notranslate">interface Applicative&lt;T&gt; {}
</code></pre></div>
<p dir="auto">Now I want to define a function f that:</p>
<ul dir="auto">
<li>takes a <code class="notranslate">Function</code> and takes a type <code class="notranslate">U</code> extending an <code class="notranslate">Applicative</code> wrapping <code class="notranslate">any</code></li>
<li>returns an <code class="notranslate">U</code> wrapping <code class="notranslate">Function</code></li>
</ul>
<p dir="auto">My naive attempts were</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="  function f&lt;U extends Applicative&gt;(fn: Function, a: U&lt;any&gt;): U&lt;Function&gt;"><pre class="notranslate"><code class="notranslate">  function f&lt;U extends Applicative&gt;(fn: Function, a: U&lt;any&gt;): U&lt;Function&gt;
</code></pre></div>
<p dir="auto">and</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="  function f&lt;T, U&lt;T&gt; extends Applicative&lt;T&gt;&gt;(fn: Function, a: U&lt;any&gt;): U&lt;Function&gt;"><pre class="notranslate"><code class="notranslate">  function f&lt;T, U&lt;T&gt; extends Applicative&lt;T&gt;&gt;(fn: Function, a: U&lt;any&gt;): U&lt;Function&gt;
</code></pre></div>
<p dir="auto">but none is valid</p>
<p dir="auto">Can we have a Generic extend a type with a generic ?</p>
<p dir="auto">This is a proposal for allowing generics as type parameters.  It's currently possible to write specific examples of monads, but in order to write the interface that all monads satisfy, I propose writing</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Monad&lt;T&lt;~&gt;&gt; {
  map&lt;A, B&gt;(f: (a: A) =&gt; B): T&lt;A&gt; =&gt; T&lt;B&gt;;
  lift&lt;A&gt;(a: A): T&lt;A&gt;;
  join&lt;A&gt;(tta: T&lt;T&lt;A&gt;&gt;): T&lt;A&gt;;
}"><pre class="notranslate"><span class="pl-s1">interface</span> <span class="pl-v">Monad</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-s1"></span><span class="pl-c1">&gt;&gt;</span> <span class="pl-kos">{</span>
  map<span class="pl-kos"></span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-kos">,</span> <span class="pl-v">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-en">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-v">A</span><span class="pl-kos">)</span> <span class="pl-c1">=</span><span class="pl-c1">&gt;</span> <span class="pl-v">B</span><span class="pl-kos">)</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span> <span class="pl-c1">=&gt;</span> <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-s1">lift</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-v">A</span><span class="pl-kos">)</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-s1">join</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">tta</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;&gt;</span><span class="pl-kos">)</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Similarly, it's possible to write specific examples of cartesian functors, but in order to write the interface that all cartesian functors satisfy, I propose writing</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Cartesian&lt;T&lt;~&gt;&gt; {
  all&lt;A&gt;(a: Array&lt;T&lt;A&gt;&gt;): T&lt;Array&lt;A&gt;&gt;;
}"><pre class="notranslate"><span class="pl-s1">interface</span> <span class="pl-v">Cartesian</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-s1"></span><span class="pl-c1">&gt;&gt;</span> <span class="pl-kos">{</span>
  all<span class="pl-kos"></span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;&gt;</span><span class="pl-kos">)</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Parametric type parameters can take any number of arguments:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Foo&lt;T&lt;~,~&gt;&gt; {
  bar&lt;A, B&gt;(f: (a: A) =&gt; B): T&lt;A, B&gt;;
}"><pre class="notranslate"><span class="pl-s1">interface</span> <span class="pl-v">Foo</span><span class="pl-c1">&lt;</span><span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-kos">,</span><span class="pl-c1">~</span><span class="pl-s1"></span><span class="pl-c1">&gt;&gt;</span> <span class="pl-kos">{</span>
  bar<span class="pl-kos"></span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-kos">,</span> <span class="pl-v">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-en">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-v">A</span><span class="pl-kos">)</span> <span class="pl-c1">=</span><span class="pl-c1">&gt;</span> <span class="pl-v">B</span><span class="pl-kos">)</span>: <span class="pl-v">T</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-kos">,</span> <span class="pl-v">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">That is, when a type parameter is followed by a tilde and a natural arity, the type parameter should be allowed to be used as a generic type with the given arity in the rest of the declaration.</p>
<p dir="auto">Just as is the case now, when implementing such an interface, the generic type parameters should be filled in:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class ArrayMonad&lt;A&gt; implements Monad&lt;Array&gt; {
  map&lt;A, B&gt;(f: (a:A) =&gt; B): Array&lt;A&gt; =&gt; Array&lt;B&gt; {
    return (arr: Array&lt;A&gt;) =&gt;  arr.map(f);
  }
  lift&lt;A&gt;(a: A): Array&lt;A&gt; { return [a]; }
  join&lt;A&gt;(tta: Array&lt;Array&lt;A&gt;&gt;): Array&lt;A&gt; {
    return tta.reduce((prev, cur) =&gt; prev.concat(cur));
  }
}"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">ArrayMonad</span><span class="pl-c1">&lt;</span><span class="pl-ent">A</span><span class="pl-c1">&gt;</span> implements Monad<span class="pl-c1">&lt;</span><span class="pl-ent">Array</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-s1">map</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-kos">,</span> <span class="pl-v">B</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-en">f</span>: <span class="pl-kos">(</span><span class="pl-s1">a</span>:<span class="pl-v">A</span><span class="pl-kos">)</span> <span class="pl-c1">=</span><span class="pl-c1">&gt;</span> <span class="pl-v">B</span><span class="pl-kos">)</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span> <span class="pl-c1">=&gt;</span> <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">B</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c1">return</span> <span class="pl-kos">(</span><span class="pl-s1">arr</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span>  <span class="pl-s1">arr</span><span class="pl-kos">.</span><span class="pl-en">map</span><span class="pl-kos">(</span><span class="pl-s1">f</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-s1">lift</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">a</span>: <span class="pl-v">A</span><span class="pl-kos">)</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span> <span class="pl-s1">return</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-kos">}</span>
  <span class="pl-s1">join</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span><span class="pl-kos">(</span><span class="pl-s1">tta</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;&gt;</span><span class="pl-kos">)</span>: <span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-v">A</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-s1">return</span> <span class="pl-s1">tta</span><span class="pl-kos">.</span><span class="pl-en">reduce</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">prev</span><span class="pl-kos">,</span> <span class="pl-s1">cur</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">prev</span><span class="pl-kos">.</span><span class="pl-en">concat</span><span class="pl-kos">(</span><span class="pl-s1">cur</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></pre></div>
<p dir="auto">In addition to directly allowing compositions of generic types in the arguments, I propose that typedefs also support defining generics in this way (see <a href="https://github.com/Microsoft/TypeScript/issues/308" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/308/hovercard">issue 308</a>):</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="typedef Maybe&lt;Array&lt;~&gt;&gt; Composite&lt;~&gt; ;
class Foo implements Monad&lt;Composite&lt;~&gt;&gt; { ... }"><pre class="notranslate"><span class="pl-s1">typedef</span> <span class="pl-v">Maybe</span><span class="pl-c1">&lt;</span><span class="pl-v">Array</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-s1"></span><span class="pl-c1">&gt;&gt;</span> <span class="pl-v">Composite</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-c1">&gt;</span> <span class="pl-kos">;</span>
<span class="pl-k">class</span> <span class="pl-v">Foo</span> <span class="pl-s1">implements</span> <span class="pl-v">Monad</span><span class="pl-c1">&lt;</span><span class="pl-v">Composite</span><span class="pl-c1">&lt;</span><span class="pl-c1">~</span><span class="pl-s1"></span><span class="pl-c1">&gt;&gt;</span> <span class="pl-kos">{</span> ... <span class="pl-kos">}</span></pre></div>
<p dir="auto">The arities of the definition and the alias must match for the typedef to be valid.</p>