2

Typescript supports function overloading, which is pretty cool, and it's possible to make a constant function overloaded like this:

interface FetchOverload {
  (action: string, method: 'post' | 'get'): object;
  (action: string): object
}

const fetch: FetchOverload = (action: string, method: 'get' | 'post' = 'get'): object { ... }

But let's suppose I want to inform the type of response expected, instead of any object. I can do this by simply replacing object with the desired type:

interface FetchOverload {
  (action: string, method: 'post' | 'get'): UserResponse;
  (action: string): UserResponse
}

const fetch: FetchOverload = (action: string, method: 'get' | 'post' = 'get'): UserResponse { ... }

If I want to go even further and instead of saying it can only return a response of type UserResponse, I could return a generic type:

interface FetchOverload<T> {
  (action: string, method: 'post' | 'get'): T;
  (action: string): T
}

const fetch: FetchOverload<T> = (action: string, method: 'get' | 'post' = 'get'): T { ... }

The problem is that for const there is no a generic type T. And in fact there isn't, I need to declare somewhere that T is a generic type, but I don't know where!

I tried everywhere and couldn't make it understand that there is a type T:

<T> const fetch: ...
const <T> fetch: ...
const fetch <T>: ...
const fetch: <T> FetchOverload<T> = ...
const fetch: FetchOverload<T> = <T> (action: ...)

The only solution I found was to transform the const function into native functions with overload:

function fetch<T>(action: string, method: 'post' | 'get'): T;
function fetch<T>(action: string): T;
function fetch<T>(action: string, method: 'post' | 'get' = 'get'): T { ... }

So what I would like to know is if in fact I need to use it this way, or if there is still some solution to keep using const.

1 Answer 1

3

I "discovered" the answer as I ended up encountering a very similar problem in this question, this question and in this answer and this answer. Basically I would just do:

interface FetchOverload {
  <T> (action: string, method: 'post' | 'get'): T;
  <T> (action: string): T
}

export const fetch: FetchOverload = <T,> (action: string, method: 'get' | 'post' = 'get'): T { ... }

Actually, the only weird thing is that comma after the type, but it's mandatory, so I don't have much to do. But it's all settled!

Sign up to request clarification or add additional context in comments.

4 Comments

For anyone wondering why it's mandatory, the comma's so that the parser doesn't confuse <T> for a JSX element.
AFAIK, the comma is mandatory in the TS playground because for some reason it treats it as JSX/TSX. It should not be needed if it's only set up to parse TS code.
you wouldn't happen to know what this type of interface declaration is called? Is there a special name, or is it just that typescript allows generic methods inside interface?
@smac89 this is called Call Signatures. You can define it as a type or an interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.