title: Conditional types ReturnType function signature overload resolution
body: <p>I'm trying to use typescript 2.8's new <a href="https://github.com/Microsoft/TypeScript/pull/21316" rel="nofollow noreferrer">conditional types</a>, (not yet released version 2.8.0-dev.20180307) and I don't know if this is a bug or just a misuse.  My focus is on my declaration of <code>MockedImplementation&lt;F&gt;</code> which can be a full function matching <code>F</code>, the return type of <code>F</code>, and if the return type of <code>F</code> is a <code>Promise</code>, then it could also be what the promise resolves to - all to be wrapped accordingly by <code>mockIt()</code>.</p>
  <pre><code>type MockedImplementation&lt;F&gt; = 
      F | // The function signature
      ((ReturnType&lt;F extends (...args: any[]) =&gt; any ? F : any&gt;) extends infer T 
          ? T extends Promise&lt;infer R&gt; 
              ? (T | R) // Or the promise or just the type that the promise resolves to
              : T // or whatever type this is
          : never);
  
  interface Wrapped&lt;T&gt; {
      result: T
  }
  
  function mockIt&lt;F&gt;(pretend : MockedImplementation&lt;F&gt;) : F {
      throw new Error('Not Implemented'); // doesn't matter
  }
  
  interface SomeOperationA {
      (parameters : { 'a': number[], 'b'?: string }) : Promise&lt;string&gt;;
  }
  
  mockIt&lt;SomeOperationA&gt;(() =&gt; Promise.resolve('hello')); //  OK
  mockIt&lt;SomeOperationA&gt;(Promise.resolve('hello')); //  OK
  mockIt&lt;SomeOperationA&gt;('hello'); //  OK
  mockIt&lt;SomeOperationA&gt;(42); //  Type error.
  </code></pre>
  <p><code>mockIt</code> of <code>SomeOperationA</code> works, perhaps directly because there are no function signature overrides.  But <code>mockIt</code> of <code>SomeOperationB</code> fails:</p>
  <pre><code>interface SomeOperationB {
      (parameters : { 'a': number[], 'b'?: string }) : Promise&lt;string&gt;;
      (parameters : { 'a': number[], 'b'?: string }, rawResponse : true) : Promise&lt;Wrapped&lt;string&gt;&gt;;
      (parameters : { 'a': number[], 'b'?: string }, rawResponse : false) : Promise&lt;string&gt;;
  }
  
  mockIt&lt;SomeOperationB&gt;(() =&gt; Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped&lt;string&gt;'.
  mockIt&lt;SomeOperationB&gt;(Promise.resolve('hello')); //  OK
  mockIt&lt;SomeOperationB&gt;('hello'); //  OK
  mockIt&lt;SomeOperationB&gt;(42); //  Type error.
  </code></pre>
  <p>It seems to be intersecting types instead of unioning them?  But I'm sure it is more nuanced than that.</p>
  <p>I saw a note somewhere about &quot;considers the last overload because presumably it is the most generalized&quot;, but I don't think it is relevant here because it doesn't seem to behave as though it matters.</p>
  <h3>Edit</h3>
  <p>@jcalz is right, makes sense:</p>
  <pre><code>interface SomeOperationB {
      (wrapped : true) : Promise&lt;Wrapped&lt;string&gt;&gt;;
      (wrapped : false) : Promise&lt;string&gt;;
  }
  
  interface Wrapped&lt;T&gt; { result: T }
  
  declare function acceptSomeOperationB(x: SomeOperationB): void;
  
  acceptSomeOperationB(() =&gt; Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped&lt;string&gt;'.
  acceptSomeOperationB(() =&gt; Promise.resolve({ result: 'hello' })); // ❌ Type '{ result: string; }' is not assignable to type 'string'.
  </code></pre>