title: How to specify return type of a promise in typescript based on the input type
body: <p>I'm trying to create a &quot;rollup&quot; service in TypeScript that can save an object based on it's type, but TypeScript is telling me I'm doing something illegal (<code>TS2322</code>).</p>
  <p>Here's a simplified version of my code; first I have an enum which describes all the object classes that I have:</p>
  <pre><code>enum ThingType {
      SomeThing = 'SomeThing',
      OtherThing = 'OtherThing',
  }
  </code></pre>
  <p>Then there's an interface that describes the base type, as well as a couple of derived types:</p>
  <pre><code>interface IThing {
      name: string;
      type: ThingType;
  }
  
  interface ISomeThing extends IThing {
      // properties of ISomeThing
  }
  
  interface IOtherThing extends IThing {
      // properties of IOtherThing
  }
  </code></pre>
  <p>For each derived type, there's a specific service that saves objects of those types:</p>
  <pre><code>function saveSomeThing(someThing: ISomeThing): Promise&lt;ISomeThing&gt; {
      return Promise.resolve(someThing);
  }
  
  function saveOtherThing(otherThing: IOtherThing): Promise&lt;IOtherThing&gt; {
      return Promise.resolve(otherThing);
  }
  </code></pre>
  <h3>The problem</h3>
  <p>Now I want to have a single &quot;rollup&quot; service that delegates the save operation to the correct implementation:</p>
  <pre><code>function saveThing&lt;T extends IThing&gt;(thing: T): Promise&lt;T&gt; {
      switch (thing.type) {
          case ThingType.SomeThing: return saveSomeThing(thing as ISomeThing);
          case ThingType.OtherThing: return saveOtherThing(thing as IOtherThing);
          default: throw new Error('Unknown type: ' + thing.type);
      }
  }
  </code></pre>
  <p>TypeScript tells me that my <code>return</code> statements are invalid:</p>
  <pre><code>TS2322: Type 'Promise&lt;ISomeThing&gt;' is not assignable to type 'Promise&lt;T&gt;'.
     Type 'ISomeThing' is not assignable to type 'T'.
       'ISomeThing' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IThing'.
  </code></pre>
  <p>That's fair enough - TypeScript doesn't know that <code>T</code> will be an <code>ISomeThing</code> for that branch of the <code>switch</code> - is there a way I can tell TypeScript that it is (without resorting to an <code>unknown</code> or <code>any</code>)?</p>