# How to Type Axios Response Data in TypeScript: A Complete Guide

> Master typing Axios JSON API responses in TypeScript. Use generics and typed helpers for precise data shapes and catch errors early. Eliminate any types.

- Repository: [Microsoft/TypeScript](https://github.com/microsoft/typescript)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Use a generic `AxiosResponse<T>` interface and a typed request helper to let TypeScript infer the exact shape of your JSON API responses, eliminating `any` types and catching contract mismatches at compile time.**

When consuming JSON APIs with **axios** in TypeScript, properly typing the response data prevents runtime errors and unlocks IDE autocompletion. The `microsoft/TypeScript` repository demonstrates this pattern through its own compiler test suite, showing how generic type inference propagates through promise-based HTTP clients. This guide explains how to **type axios response typescript** patterns using the same mechanisms that power the TypeScript compiler itself.

## Why Generic Type Inference Matters for Axios

TypeScript’s type system can propagate generic arguments through promise-based APIs. In the `microsoft/TypeScript` test suite, you can see this pattern in [`tests/cases/compiler/destructureOfVariableSameAsShorthand.ts`](https://github.com/microsoft/TypeScript/blob/main/tests/cases/compiler/destructureOfVariableSameAsShorthand.ts):

```typescript
interface AxiosResponse<T = never> {
    data: T;
}

declare function get<T = never, R = AxiosResponse<T>>(): Promise<R>;

```

The `get` declaration is generic over `T` (the payload) and returns a `Promise` of `AxiosResponse<T>`. The compiler automatically infers `T` from the call site. This is the same mechanism you can employ with **axios**.

The core of this inference lives in the compiler’s type-checker (see [`src/compiler/checker.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/checker.ts)), where generic signatures are instantiated and the resulting type is substituted throughout the call expression. When you use a default type parameter of `T = never`, TypeScript raises an error if the payload type isn’t supplied or inferred, preventing accidental `any` leakage.

## Step-by-Step: Typing Axios JSON Responses

### 1. Define Your API Payload Interfaces

Start by describing the JSON payload with explicit interfaces. This creates the contract between your application and the API.

```typescript
// src/api/types.ts
export interface User {
    id: number;
    name: string;
    email: string;
}

export interface Post {
    id: number;
    title: string;
    body: string;
    userId: number;
}

```

### 2. Create a Generic Response Wrapper

Mirror the axios response shape with a generic interface that defaults to `never`. This forces consumers to specify a type or rely on inference.

```typescript
// src/api/axiosResponse.ts
export interface AxiosResponse<T = never> {
    data: T;
    status: number;
    statusText: string;
    headers: Record<string, string>;
}

```

### 3. Build a Typed Request Helper

Write a wrapper function that forwards the generic type argument to axios. This centralizes configuration and ensures the return type propagates correctly.

```typescript
// src/api/client.ts
import axios, { AxiosRequestConfig } from "axios";
import { AxiosResponse } from "./axiosResponse";

/**
 * Generic GET request – infers the response payload type.
 *
 * @param url The endpoint URL
 * @param config Optional axios config
 * @returns Promise resolving to a typed AxiosResponse<T>
 */
export async function get<T = never>(
    url: string,
    config?: AxiosRequestConfig
): Promise<AxiosResponse<T>> {
    const raw = await axios.get<T>(url, config);
    // Map axios's own response shape to our wrapper
    return {
        data: raw.data,
        status: raw.status,
        statusText: raw.statusText,
        headers: raw.headers,
    };
}

```

Notice the `<T>` on `axios.get<T>`—this tells axios what shape to expect for `raw.data`. The wrapper then returns a consistent `AxiosResponse<T>` that you control across the codebase.

### 4. Consume with Full Type Safety

When you call the helper, TypeScript infers the concrete type from your generic argument, giving you a strongly typed `response.data`.

```typescript
// src/example/usage.ts
import { get } from "../api/client";
import { User, Post } from "../api/types";

async function fetchUser() {
    // T is explicitly set to User
    const response = await get<User>("/api/users/42");
    // response.data is strongly typed as User
    console.log(`Name: ${response.data.name}`);
}

async function fetchPosts() {
    // T is inferred as Post[] from the generic argument
    const { data: posts } = await get<Post[]>("/api/posts");
    posts.forEach(p => console.log(p.title));
}

```

**What you gain:**

* `response.data` is **never** `any`.
* IDE autocompletion and refactoring work flawlessly.
* Compile-time errors catch mismatched fields (e.g., missing `email` on `User`).

## Handling Dynamic and Union Types

If an endpoint returns multiple possible shapes, preserve safety using **discriminated unions**:

```typescript
type SearchResult = User | Post;

async function search(query: string) {
    const { data } = await get<SearchResult[]>("/api/search", { params: { q: query } });
    data.forEach(item => {
        if ("email" in item) {
            // TypeScript narrows to User
            console.log(item.email);
        } else {
            // Narrowed to Post
            console.log(item.title);
        }
    });
}

```

## Summary

* **Define interfaces** that mirror your JSON API payloads to create compile-time contracts.
* **Use a generic `AxiosResponse<T>`** with a default of `never` to prevent untyped data leakage.
* **Wrap axios calls** in a typed helper function that forwards the generic `<T>` to `axios.get<T>`, ensuring the compiler propagates types through the promise chain.
* **Leverage type inference** at the call site so `response.data` is automatically typed without manual annotation on every request.
* **Apply discriminated unions** for endpoints that return heterogeneous data, maintaining type safety through narrowing.

## Frequently Asked Questions

### How do I type axios response data without using generics?

You can explicitly cast the response using type assertions (e.g., `response.data as User`), but this bypasses compile-time safety and shifts errors to runtime. The generic approach shown in [`tests/cases/compiler/destructureOfVariableSameAsShorthand.ts`](https://github.com/microsoft/TypeScript/blob/main/tests/cases/compiler/destructureOfVariableSameAsShorthand.ts) is preferred because it uses TypeScript’s inference engine to validate the shape at compile time.

### What is the difference between AxiosResponse and a custom response interface?

The built-in `AxiosResponse<T>` from the `axios` package includes additional properties like `config` and `request` that may expose internal axios details. A custom interface (as demonstrated in [`src/api/axiosResponse.ts`](https://github.com/microsoft/TypeScript/blob/main/src/api/axiosResponse.ts)) lets you control exactly which fields are exposed to your application, ensuring a stable contract even if axios internals change.

### How can I handle errors with typed axios responses in TypeScript?

Axios errors are typically typed as `AxiosError`, which accepts a generic for the error response body. You can narrow error types using `instanceof AxiosError` checks, then access `error.response?.data` with the appropriate type. This maintains type safety in both success and failure paths without reverting to `any`.

### Does TypeScript infer axios response types automatically?

No, TypeScript cannot infer the specific JSON structure of an external API without explicit type annotations or generics. As shown in the `microsoft/TypeScript` source analysis, you must provide a generic argument (e.g., `axios.get<User>`) or a wrapper function that propagates the generic type parameter, allowing the compiler to substitute the concrete type throughout the call chain.