1

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'.
user3056783
  • 2,265
  • 1
  • 29
  • 55
  • I feel you are doing the whole overloading wrong. Function/method overload happens when each function or method has a different number of arguments but the same name, and the same return type. Yours violate the conditions. – Kelvin Ukuejubola Oritsetimeyi Oct 20 '22 at 09:05
  • The example provided is constrained on purpose, I'm actually trying to satisfy a compiler because such a definition is provided by external library. So it's probably issue with the definitions. However I think it's allowed to have different return type, see https://stackoverflow.com/a/24222144/3056783 – user3056783 Oct 20 '22 at 09:08
  • 1
    @KelvinUkuejubolaOritsetimeyi - that is not true. Function overloading in TypeScript allows different parameter and return types. This is more or less a common use case. – Tobias S. Oct 20 '22 at 09:11

1 Answers1

2

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

Tobias S.
  • 21,159
  • 4
  • 27
  • 45