Home > OS >  Pass generic using function.apply in Typescript
Pass generic using function.apply in Typescript

Time:01-10

I'm coding a personal project (I first started the project as Javascript) where some http requests have to be made. To do that, I decided to use Axios. So, I created a file named http.js with the following content.

import axios from 'axios';

const baseURL = '/api';

const requestWrapper = async (request, { url, options, data }) => {
  const config = { baseURL, ...options };

  const requestObject = await request.apply(
    this,
    data ? [url, data, config] : [url, config]
  );
  const requestData = requestObject.data;

  return { status: requestObject.status, data: requestData };
};

const get = async (url, options) => {
  try {
    return await requestWrapper(axios.get, { url, options });
  } catch (error) {
    return error.response;
  }
};

const remove = async (url, options) => {
  try {
    return await requestWrapper(axios.delete, { url, options });
  } catch (error) {
    return error.response;
  }
};

const post = async (url, data, options) => {
  try {
    return await requestWrapper(axios.post, { url, data, options });
  } catch (error) {
    return error.response;
  }
};

const put = async (url, data, options) => {
  try {
    return await requestWrapper(axios.put, { url, data, options });
  } catch (error) {
    return error.response;
  }
};

const patch = async (url, data, options) => {
  try {
    return await requestWrapper(axios.patch, { url, data, options });
  } catch (error) {
    return error.response;
  }
};

export { get, remove, post, put, patch };

What I did in the last code snippet is encapsulate each http request into a function named similarly. This was done to make easier the code in case the http client library (Axios) were changed.

The thing is that now I want to convert this file to Typescript. The specific problem I have, is that in the previous code I made a wrapper function because the calls for each http function are very similar, this wrapper function should receive a generic T to pass it through the Axios function in order to type the response. However, I don't know how to pass this generic because in the following function:

const requestWrapper = async (request, { url, options, data }) => {
  const config = { baseURL, ...options };

  const requestObject = await request.apply(
    this,
    data ? [url, data, config] : [url, config]
  );
  const requestData = requestObject.data;

  return { status: requestObject.status, data: requestData };
};

Specifically:

 const requestObject = await request.apply(
    this,
    data ? [url, data, config] : [url, config]
  );

I don't know a way where i can specify the generic. What should I do?

I searched but didn't find something specific like my problem. I have thought to remove the internal wrapper and call each Axios function inside its specific encapsulation function.

CodePudding user response:

Since Function#apply is weakly typed, you're gonna have to use a type cast if you want a stronger type:

    const requestObject = await (request.apply(
        this,
        data ? [url, data, config] : [url, config]
    ) as ReturnType<typeof request<T>>)

Full code:

const requestWrapper = async <T>(request:
    typeof axios.get |
    typeof axios.post |
    typeof axios.put |
    typeof axios.patch |
    typeof axios.delete
    , { url, options, data }) => {
    const config = { baseURL, ...options };

    const requestObject = await (request.apply(
        this,
        data ? [url, data, config] : [url, config]
    ) as ReturnType<typeof request<T>>)
    const requestData = requestObject.data;

    return { status: requestObject.status, data: requestData };
};
  • Related