Search code examples
typescriptoverloading

How to implement overloaded function in Typescript?


I have a following definition of SRequest object:

type SRequest = {
  headers: string[];
  get(header: string): string;
  get(header: 'Set-Cookie'): string[];
}

const myReq: SRequest = {
  headers: [ 'a' ],
  get: (header: string | 'Set-Cookie'): string | string[] => {
    if (header === 'Set-Cookie') {
      return [ 'x' ];
    }
    return '';
  }
}

But it fails to compile. I thought with overloaded function I can use union type for different arguments but I get this error:

Error:

Type '(header: string | 'Set-Cookie') => string | string[]' is not assignable to type '{ (header: string): string; (header: "Set-Cookie"): string[]; }'.
  Type 'string | string[]' is not assignable to type 'string'.
    Type 'string[]' is not assignable to type 'string'.

Solution

  • The TypeScript compiler only has limited ways of understanding function implementations. It basically just looks what the the type of each return statement is and creates a union of those types. In this case, that would result in string | string[] which conflicts with your overloads.

    It probably feels like an unsatisfying solution, but forcefully silencing the error with an assertion might be the only way.

    const myReq: SRequest = {
      headers: [ 'a' ],
      get: (header) => {
        if (header === 'Set-Cookie') {
          return [ 'x' ] as string & string[]
        }
        return '' as string & string[]
      }
    }
    

    The overload definition demands that the implementation must return a string and a string[] to satisfy both overloads; hence the interseciton. While not being truly type-safe, it would at least give some warnings when you would try to return a number for example.


    Playground