typescriptoverloadingtypescript-typingstypescript-generics

Failed to implement Typescript function overload


Following the last question: Typescript: omit undefined/null properties from type

Using TS, I was trying to implmenet an overload for a function named request which can accept payload or not, by the TEndpointsPayload(code below) (When property contain null, there is no need to pass payload),

Giving the following types:

export type TEndpointsPayload = {
    getList: null, //No payload required
    open: {
        name: string
    }
    close: {
        name: string
    }
}

export type TEndpointsWithPayload = {
    [K in keyof TEndpointsPayload as TEndpointsPayload[K] extends null ? never : K]: TEndpointsPayload[K]; //Contains the 'open' | 'close'
}; //Will create a type: {'open': {name: string}, 'close': {name: string}}

export type TEndpointsWithoutPayload = {
    [K in keyof TEndpointsPayload as TEndpointsPayload[K] extends null ? K : never]: TEndpointsPayload[K]; //Contains only the 'getList'
}; //Will create a type: {'getList': null}

This is the function overload implementation

//This overload signature is not compatible with its implementation signature.ts(2394)
  private async request<T extends keyof TEndpointsWithoutPayload>(endpointName: T): Promise<TEndpointsResponse[T]>;

//Code never fall into this implementation
  private async request<T extends keyof TEndpointsWithPayload>(endpointName: T, payload: TEndpointsWithPayload[T]): Promise<TEndpointsResponse[T]> { ... }

Currently I'm having 2 issues, one is where the first request function having error

This overload signature is not compatible with its implementation signature.ts(2394)

Which is solved when adding ? to the payload argument (but not what I'm intended to do as payload should not be optional, but required/not exist depends on the TEndpointsPayload)

and second, is where any usage of those methods, fall to the first request implemenmtation (aka: only allow to pass request('getList') without a payload).

I didn't manage to have the following behavior:

request('getList')//OK
request('open', {name}) //OK
request('getList', {test}) //ERROR, no payload allow
request('open') // ERROR, payload required

Thank you! Any hint or help would be much appreciated!


Solution

  • Shorty after posting this question, I've come into the solution. Apparently there is need to declare both the function scenarios and the implement a third one which handle all of those. So the correct function overload will look like this:

        private async request<T extends keyof TEndpointsWithoutPayload>(endpointName: T): Promise<TEndpointsResponse[T]>;
        private async request<T extends keyof TEndpointsWithPayload>(endpointName: T, payload: TEndpointsWithPayload[T]): Promise<TEndpointsResponse[T]>;
        private async request<T extends keyof TEndpointsPayload>(endpointName: T, payload?: TEndpointsPayload[T]): Promise<TEndpointsResponse[T]> {
    //handle both scenarios
    }
    

    Hope it helps to anyone come across the same question!