typescriptoverloading

Typescript Function Overload Parameters


I am trying to create a function overload for an API call with a delete method. Here's what I have so far:

type ApiCore = { endpoint: string; key: string };

export type ApiParams = {
  routeParam?: string;
  queryParams?: FormatQueryParams;
};

function deleteApi(
  core: ApiCore
): (ids: string[], params?: ApiParams) => Promise<string[]>;
function deleteApi<Schema>(
  core: ApiCore
): (params: ApiParams, param2?: ApiParams) => Promise<Schema & BaseSchema>;
function deleteApi<Schema>({
  endpoint,
  key,
}: ApiCore): (
  param1: string[] | ApiParams,
  param2?: ApiParams
) => Promise<(Schema & BaseSchema) | string[]> {
  return async function (param1, param2 = {}) {
    if (Array.isArray(param1)) {
      const { queryParams, routeParam } = param2;

      const { data } = await api.delete(
        `${endpoint}${routeParam ? `/${routeParam}` : ''}${formatQueryParams(
          queryParams
        )}`,
        { data: { [key]: param1 } }
      );

      return data.result || data.data;
    }

    const { queryParams, routeParam } = param1;
    const { data } = await api.delete(
      `${endpoint}${routeParam ? `/${routeParam}` : ''}${formatQueryParams(
        queryParams
      )}`
    );

    return data.result || data.data;
  };
}

The function is being curried because it will be passed to a factory function that creates other requests. As you can see, the inner asynchronous function requires at least one argument, which can either be string[] or ApiParams object. The problem is that whenever I would pass in an array of strings, Typescript complains that Type 'string[]' has no properties in common with type 'ApiParams' such as in this implementation:

const service = (endpoint: string, key: string) => ({
  delete: (param1: string[] | ApiParams, param2?: ApiParams) => 
    deleteApi({ endpoint, key })(param1, param2)
    //                           ^Type 'string[]' has no properties in common with type 'ApiParams'
})

I'm confused, shouldn't it accept it? Thank you.


Solution

  • I guess you are overcomplicating, just return an overloaded function and use it directly:

    Playground

    type ApiCore = { endpoint: string; key: string };
    type FormatQueryParams = {};
    type BaseSchema = {};
    
    export type ApiParams = {
      routeParam?: string;
      queryParams?: FormatQueryParams;
    };
    
    function deleteApi({  endpoint,  key,}: ApiCore)
     {
      function out(ids: string[], params?: ApiParams): Promise<string[]>;
      function out(params: ApiParams, params2?: ApiParams): Promise<BaseSchema>
      async function out(param1: string[] | ApiParams, param2: ApiParams = {}){
        return 1 as any;
      }
      return out;
    }
    
    const service = (endpoint: string, key: string) => ({
      delete: deleteApi({ endpoint, key })
    });
    
    const s = service('','');
    
    s.delete([]).then(r =>{
      r; // string[]
    });