title: How to make one generic type closely dependent on another in TypeScript?
body: <p>I'm looking for a way to make my code more type-safe and would like to define a close relationship between some of my types when passing them to generic functions.</p>
  
  <p>For example, for the given set of types:</p>
  
  <pre><code>interface FooParam {}
  interface FooReturn {}
  
  interface BarParam {}
  interface BarReturn {}
  </code></pre>
  
  <p>and the following function:</p>
  
  <pre><code>function action&lt;T, R&gt;(foo: T): R
  </code></pre>
  
  <p>I'd like to closely bind <code>FooParam</code> with <code>FooReturn</code>, and <code>BarParam</code> with <code>BarReturn</code>, so the compiler allows the call only if a pair of associated types is passed as <code>T</code> and <code>R</code> and returns an error otherwise.</p>
  
  <pre><code>action&lt;FooParam, FooReturn&gt;(...) // bound types, OK
  action&lt;BarParam, BarReturn&gt;(...) // bound types, OK
  
  action&lt;FooParam, BarReturn&gt;(...) // types are not bound, ERROR
  action&lt;FooParam, string&gt;(...) // types are not bound, ERROR
  </code></pre>
  
  <p>I've actually managed to achieve the above by defining two base interfaces, which will be later used as constraints on the generic types:</p>
  
  <pre><code>interface Param {}
  interface Return&lt;T extends Param&gt;{
      _typeGuard?: keyof T
  }
  
  interface FooParam extends Param {}
  interface FooReturn extends Return&lt;FooParam&gt; {}
  
  interface BarParam extends Param {}
  interface BarReturn extends Return&lt;BarParam&gt; {}
  
  function action&lt;T extends Param, R extends Return&lt;T&gt;&gt;(foo: T): R
  </code></pre>
  
  <p>However this seems more like a workaround than a clean solution, especially given the <code>_typeGuard?: keyof T</code> field, which exists only so <code>T</code> actually matters and is checked, not ignored. Another downside is that every type must extend one of my custom interfaces, which sometimes is just not possible.</p>
  
  <p>Is there a better and more universal way to get the described functionality?</p>