title: How to type a function with different combinations of arguments? Similar to method overloading
body: <p>I have the following function that I would like to be able to call in at least 3 different ways:</p>
  <pre><code>setBody(payload: Record&lt;string, unknown&gt;);
  setBody(payload: string | Record&lt;string, string&gt;, type: 'urlencoded');
  setBody(payload: Blob, type: 'blob');
  </code></pre>
  <p>To implement this function I tried the following:</p>
  <pre><code>type Payload&lt;T extends 'json' | 'urlencoded' | 'blob'&gt; =
    T extends 'json'
      ? Record&lt;string, unknown&gt;
      : T extends 'urlencoded'
        ? string | Record&lt;string, string&gt;
        : Blob;
  
  export const setBody = &lt;T extends 'json' | 'urlencoded' | 'blob'&gt;(
    payload: Payload&lt;T&gt;, 
    type: T,
  ): BodyInit =&gt; {
    let body;
  
    switch (type) {
      case 'json':
        body = JSON.stringify(payload);
        break;
      case 'urlencoded':
        body = new URLSearchParams(payload);
        break;
      default:
        body = payload;
    }
  
    return body;
  };
  </code></pre>
  <p>However, I get the following error:</p>
  <pre><code>Type 'Record&lt;string, unknown&gt; | (T extends &quot;urlencoded&quot; ? string | Record&lt;string, string&gt; : Blob)' is not assignable to type 'string | URLSearchParams | Record&lt;string, string&gt; | string[][] | undefined'.
      Type 'Record&lt;string, unknown&gt;' is not assignable to type 'string | URLSearchParams | Record&lt;string, string&gt; | string[][] | undefined'.
        Type 'Record&lt;string, unknown&gt;' is not assignable to type 'string'.
          Type 'string | Record&lt;string, unknown&gt; | Blob | Record&lt;string, string&gt;' is not assignable to type 'string | URLSearchParams | Record&lt;string, string&gt; | string[][] | undefined'.
            Type 'Record&lt;string, unknown&gt;' is not assignable to type 'string | URLSearchParams | Record&lt;string, string&gt; | string[][] | undefined'.
              Type 'Record&lt;string, unknown&gt;' is not assignable to type 'string'.
                Type 'Payload&lt;T&gt;' is not assignable to type 'string[][]'.
                  Type 'Record&lt;string, unknown&gt; | (T extends &quot;urlencoded&quot; ? string | Record&lt;string, string&gt; : Blob)' is not assignable to type 'string[][]'.
                    Type 'Record&lt;string, unknown&gt;' is missing the following properties from type 'string[][]': length, pop, push, concat, and 26 more.
                      Type 'string | Record&lt;string, unknown&gt; | Blob | Record&lt;string, string&gt;' is not assignable to type 'string[][]'.
                        Type 'string' is not assignable to type 'string[][]'.
  </code></pre>
  <p>Why, though? If I add a <code>case</code> to the <code>switch</code> that is neither of the above then TypeScript can determine that it will never be reached. But somehow it can't determine that if the type is <code>urlencoded</code> then <code>payload</code> will either be <code>string</code> or <code>Record&lt;string, string&gt;</code>. Am I missing something? Or ss this simply not possible?</p>
  <p>Help would be greatly appreciated, thank you!</p>