title: Async function that returns a Promise or String - Typescript
body: <p>Is it possible to return not just a Promise from a function?</p>
  
  <pre><code>const someFunc = async &lt;T&gt;(url: string): Promise&lt;T&gt; =&gt; {
    const res = await fetch(url);
  
    if (!res.ok) return { error: 'error text' };
    return await res.json();
  }
  </code></pre>
  
  <p>Depending on the condition, function above can return a promise or an object with <code>{ error: 'string' }</code>. I'm getting an error here: <code>TS2322: Type '{ error: any; }' is not assignable to type 'T'.   '{ error: any; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.</code></p>
  
  <p>I've tried to use:</p>
  
  <pre><code>const someFunc = async &lt;T&gt;(url: string): Promise&lt;T&gt; | Promise&lt;string&gt; =&gt; {}
  </code></pre>
  
  <p>This throws an error: <code>TS1055: Type 'Promise&lt;T&gt; | Promise&lt;string&gt;' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.</code></p>
  
  <p>Also i've tried this variant:</p>
  
  <pre><code>const someFunc = async &lt;T&gt;(url: string): Promise&lt;T | { error: string }&gt; =&gt; {}
  </code></pre>
  
  <p>But when i consume this function:</p>
  
  <pre><code>interface IResponse {
    access_token: string;
    refresh_token: string;
    userRoles: string[];
    error: any;
  }
  
  const result = await someFunc&lt;IResponse&gt;(url);
  console.log(result.access_token); // throws an error
  // TS2339: Property 'access_token' does not exist on type '{ error: string; } | IResponse'.   Property 'access_token' does not exist on type '{ error: string; }'.
  </code></pre>
  
  <p><strong>UPDATE with type guard</strong></p>
  
  <pre><code>If ('access_token' in result) {
    console.log(result.access_token);
  }
  </code></pre>
  
  <p>this works fine, uses <code>access_token</code> from <code>IResponse</code> interface.</p>