What is the correct way to add type annotations to an Axios request?

I have meticulously added type annotations to all endpoints in my API using the openapi-typescript package.

Now, I am looking to apply these annotations to my Axios requests as well. Here is a snippet of code from a Vue.js project I have been developing:

type FactRepeater = components['schemas']['FactRepeater'];
type FactRepeaterResponse =
  paths['/api/v1/repeaters/fact-repeater/']['get']['responses']['200']['content']['application/json'];
type FactRepeaterRequest =
  paths['/api/v1/repeaters/fact-repeater/']['get']['parameters']['query'];

const repeaters: Ref<Array<FactRepeater>> = ref([]);

async function requestRepeaters(
  limit: number,
  offset: number,
  ordering: string | null = null,
): Promise<void> {
  try {
    const response: AxiosResponse<FactRepeaterResponse, FactRepeaterRequest> =
      await api.get('/api/v1/repeaters/fact-repeater/', {
        params: { limit, offset, ordering },
      });
    // These fields aren't null because this only happens on success
    repeaters.value = response.data.results!;
    pagination.value.rowsNumber = response.data.count!;
  } catch (error) {
    console.error(error);
  }
}

The relevant sections of the components schema are shown below:

// ...
    // components["schemas"]
    FactRepeater: {
      id: number;
      // ...
    };
// ...
    PaginatedFactRepeaterList: {
      count?: number;
      next?: string | null;
      previous?: string | null;
      results?: components["schemas"]["FactRepeater"][];
    };
// ...
    // paths['/api/v1/repeaters/fact-repeater/']['get']
    responses: {
      200: {
        content: {
          "application/json": components["schemas"]["PaginatedFactRepeaterList"];
        };
      };
    };
    parameters: {
      query?: {
        ordering?: string;
        limit?: number;
        offset?: number;
        // ...
      };
    };
// ...

However, upon inspecting the code further, I realized that the descriptions of types could be improved. For instance, when I hover over params in my IDE, it does not provide the expected information based on the filled-in AxiosResponse.

https://i.sstatic.net/AxLLZ.png

This issue made me reconsider how the request type should be properly written for the AxiosResponse. What modifications do I need to make?

As a follow-up question: How should the request type be defined in situations where an endpoint has no configurable request parameters, but only the endpoint itself?

Answer №1

Axios lacks extensive configurability, unfortunately. It doesn't offer much room for customizing the response type unless you set the first generic type of request functions as unknown, especially if you've used any response interceptors. This is why I prefer to override it boldly with my own typing system, which allows for greater customization.

import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios';

type CustomAxiosRequestConfig<T> = Omit<AxiosRequestConfig, 'params'> & {params: T};
type CustomInstancePromises = {
  get<T, U>(url: string, config?: CustomAxiosRequestConfig<U>): Promise<T>;
  post<T, U>(url: string, data?: unknown, config?: CustomAxiosRequestConfig<U>): Promise<T>;
  put<T, U>(url: string, data?: unknown, config?: CustomAxiosRequestConfig<U>): Promise<T>;
  patch<T, U>(url: string, data?: unknown, config?: CustomAxiosRequestConfig<U>): Promise<T>;
  delete<T, U>(url: string, config?: CustomAxiosRequestConfig<U>): Promise<T>;
};

type AxiosInstanceType = CustomInstancePromises & AxiosInstance;

const axiosInstance = axios.create({
  baseURL: BASE_URL
}) as AxiosInstanceType;

// example:
axiosInstance.get<ResponseType, ParamsObjectType>(url, {params: {...}); // params will be inferred properly

The first generic type represents your response type (eliminating the need to write

<unknown, PostInterceptedShape>
), while the second generic type replaces the default params: any in Axios's typing system with your desired params type, allowing for further customization of its type system. Although not perfect, this workaround provides more flexibility than what Axios offers out of the box.

It's worth noting that using an interface for AxiosInstanceType won't work due to errors with extends; instead, type intersection must be utilized for overriding purposes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing NgClass Within an Attribute Directive in Angular 2.4.0

Is there a way to utilize NgClass within a custom attribute directive to modify the CSS class of the main elements? For example, if I have this code snippet: @Component({ selector: 'my-app', template: ` <div> <div class=" ...

Trouble with React Context State Refreshing

Exploring My Situation: type Props = { children: React.ReactNode; }; interface Context { postIsDraft: boolean; setPostIsDraft: Dispatch<SetStateAction<boolean>>; } const initialContextValue: Context = { postIsDraft: false, setPostIs ...

Angular 4: Transform a string into an array containing multiple objects

Recently, I received an API response that looks like this: { "status": "success", "code": 0, "message": "version list", "payload" : "[{\"code\":\"AB\",\"short\":\"AB\",\"name\":\"Alberta&b ...

Vue JS - Show the second option in the select menu once the first option is disabled

Can anyone assist me with displaying the second option in a select drop-down menu after the menu is disabled? The select menu will be disabled if there are only two options available. However, instead of showing the default 'Select nationality' ...

Tips for accessing the data type of a nested property in TypeScript

If I want to keep the following declarations as they are, how can I specifically retrieve the type of the members property? export type Members = { __typename?: 'Members'; id?: Maybe<Scalars['String']>; ... }; export type P ...

Is there a way to dynamically adjust the size of an image in NodeJS utilizing Sharp, when only provided with a URL, employing async/await, and ensuring no local duplicate is

In my current work environment, the only image processing library available is NodeJS's Sharp for scaling images. It has been reliable due to its pipe-based nature, but now I have been given the task of converting it to TypeScript and utilizing Async/ ...

Having trouble getting code hints to function properly with the official TypeScript plugin on Sublime Text 3

I am experiencing issues with getting code hinting to work using the official TypeScript plugin for Sublime Text 3 on Mac OSX 10.10.5 with Sublime 3. Despite installing it in the packages directory, I am unable to see any code hints. In accordance with th ...

When you make a POST request to an express API, the properties are not clearly defined

Just getting into Vue.JS and experimenting with creating a basic MEVN to-do list app for practice. I keep encountering an issue when trying to send a POST request to my express server, receiving the error message: TypeError: Cannot read properties of unde ...

Configure Cross-Origin Resource Sharing in Nuxt using Express middleware

I have a Nuxt application with Express middleware located in src/api/* and I need to set up CORS for this middleware so that another frontend application (on a different domain) can send requests to it. Unfortunately, the code below is not functioning as ...

Struggling to obtain the Variable

Trying to send a POST request to my ESP8266 HTTP Server, I need to transmit 4 variables: onhour, offhour, onminute, offminute. These variables should be retrieved from a timepicker-component imported from "ng-bootstrap" Despite numerous attempts over the ...

How can I display Vue object properties in the header section?

I have a table displaying various properties of people. In anticipation of future extensions to these properties, I want to list all available properties in the table header and provide corresponding answers in the table body. To access a person's pr ...

Guide on creating a similar encryption function in Node JS that is equivalent to the one written in Java

In Java, there is a function used for encryption. public static String encryptionFunction(String fieldValue, String pemFileLocation) { try { // Read key from file String strKeyPEM = ""; BufferedReader br = new Buffer ...

What is the best way to set up a JSON attribute with properly formatted JSON data?

Within this code snippet, the variable some is assigned a JSON string that requires expansion and proper indentation for improved readability. export class MyComponent implements OnInit { some:any = JSON.parse('[{"id":"EN","fill":"blue","classb ...

Issue with Typescript and React: Property not found on type 'IntrinsicAttributes'

While working on my app using Meteor, React, and Typescript, I encountered a transpiling error: The property 'gameId' is not recognized in the type 'IntrinsicAttributes & {} & { children?: ReactNode; } In my project, I have a com ...

Guide to retrieving the button value upon clicking in vue.js

There are multiple buttons on a web page all linked to the same function webcamSendRequestButton <button v-on:click="webcamSendRequestButton" value="0" type="button" class="webcam-send-request-button" :disabled="disabled">Verify</button> <b ...

Using an image as a button in Vue.js: A step-by-step guide

I'm currently working on creating a login button within a single-file-component using Vue.js in my Rails application with a Vue.js front-end. The purpose of this button is to redirect users to an external login page when clicked. I am wondering how I ...

Steps for determining if a string is compatible with a user-defined type in Typescript

Just getting started with Typescript and currently working on a sudoku game. Here are the types and interface I have set up: export type GridCellValue = 1|2|3|4|5|6|7|8|9; export interface GridCell { readonly: boolean, value: GridCellValue|null, } ex ...

Creating an RxJS observable stream from an event emitted by a child element in an Angular 2 component template

Currently incorporating Angular 2.0.0-rc.4 alongside RxJS 5.0.0-beta.6. In the midst of exploring various methods for generating observable streams from events, I find myself inundated with choices and would like to gather opinions. Recognizing that there ...

Is it feasible to make references to interfaces from an extended interface in Typescript?

I had the idea of enhancing all interfaces in HTMLElementTagNameMap with chained functionality. Since there are numerous interfaces, and all elements either are HTMLElement or extend it, I wanted a way to achieve something like this: interface HTMLElement ...

What is the process for upgrading TypeScript to the latest version?

Is there a way to upgrade TypeScript version for ASP.net MV5 project in Visual Studio 2015? I attempted searching through Nuget but couldn't locate it. There seems to be an issue with the razor intellisense (index.d.ts file) and I'm hoping that ...