Skip to content

[codex] fix transformRequest input typing#10745

Merged
jasonsaayman merged 5 commits intoaxios:v1.xfrom
atharvasingh7007:codex/fix-request-transformer-input-typing
Apr 26, 2026
Merged

[codex] fix transformRequest input typing#10745
jasonsaayman merged 5 commits intoaxios:v1.xfrom
atharvasingh7007:codex/fix-request-transformer-input-typing

Conversation

@atharvasingh7007
Copy link
Copy Markdown
Contributor

@atharvasingh7007 atharvasingh7007 commented Apr 17, 2026

Summary

  • make AxiosRequestTransformer generic over the request data type
  • thread that generic through AxiosRequestConfig<D>.transformRequest
  • add ESM/CJS module typing coverage for generic request transformers
  • make the module fixture helpers link the local checkout so module tests validate this repo instead of any parent-installed axios

Root cause

AxiosRequestConfig<D> carried the request data type, but transformRequest always received data: any, so transformer implementations lost type information even when the surrounding request config was generic.

The module typing fixtures also created temporary projects without a local axios package entry, which let TypeScript resolve a higher-level installed copy instead of the current checkout. That made the new typing assertions unreliable until the fixture helpers were pointed at the local repo.

Testing

  • npm run build
  • npm run test:module:esm
  • npm run test:module:cjs

Fixes #10744


Summary by cubic

Fix TypeScript typings so transformRequest receives the correct data type and make response transformers generic. Improve ESM/CJS typing tests by linking the local axios and adding cases for generic request transformers.

Description

  • Summary of changes

    • Made AxiosRequestTransformer<D> generic and threaded D through AxiosRequestConfig<D>.transformRequest.
    • Made AxiosResponseTransformer<T> generic over response data.
    • Added ESM/CJS TS tests for generic request transformers; run with --noEmit and higher timeouts.
    • Updated ESM/CJS fixture helpers to accept repoRoot and symlink the local axios; tests pass repoRoot (or null) and clean up temp fixtures.
  • Reasoning

    • Preserve request/response data types in transformers for compile-time safety.
    • Ensure module typing tests validate this repo by resolving the local axios, fixing previous failing tests.
  • Additional context

Docs

  • No user-facing docs needed. Optional: add a brief changelog note under Types.

Testing

  • Added TS-only typing tests for generic request transformers in both ESM and CJS.
  • Hardened module fixtures to link the local repo when repoRoot is provided; tests use --noEmit, increased timeouts, and clean up temp dirs.
  • Commands: npm run build; npm run test:module:esm; npm run test:module:cjs.

Semantic version impact

Patch: Type-only improvements with no runtime changes.

Written for commit 3228da4. Summary will update on new commits.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 11 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

@atharvasingh7007 atharvasingh7007 marked this pull request as ready for review April 17, 2026 20:10
@jasonsaayman jasonsaayman force-pushed the codex/fix-request-transformer-input-typing branch from a381472 to f5a1fa9 Compare April 25, 2026 17:13
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/module/esm/tests/ts.module.test.js">

<violation number="1" location="tests/module/esm/tests/ts.module.test.js:25">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**

This test no longer validates repo-local axios resolution because it omits the local checkout symlink, leaving the PR’s behavior change untested.</violation>
</file>

<file name="tests/module/cjs/tests/ts-require-default.module.test.cjs">

<violation number="1" location="tests/module/cjs/tests/ts-require-default.module.test.cjs:26">
P1: Passing null removes the local checkout symlink, so this test no longer reliably validates the current axios repo.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread tests/module/cjs/tests/ts-require-default.module.test.cjs
Comment thread tests/module/esm/tests/ts.module.test.js
@jasonsaayman jasonsaayman merged commit 694f1ec into axios:v1.x Apr 26, 2026
22 checks passed
@salisbury-espinosa
Copy link
Copy Markdown

salisbury-espinosa commented Apr 26, 2026

It seems to me that perhaps this PR is invalid.
related comments:
#10744 (comment)

in short, the argument data cannot be of type of D because of this:

https://github.com/axios/axios/blob/main/lib/core/transformData.js#L22

utils.forEach(fns, function transform(fn) {
   data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
 });

data is the result type of the function fn and and this is now ==> any

export interface AxiosRequestTransformer<D = any> {
  (this: InternalAxiosRequestConfig<D>, data: D, headers: AxiosRequestHeaders): any;

argument has type of D before the first execution of fn.
and to improve type safety we need to attach a constraint to the result of AxiosRequestTransformer (replace any with D | string | Buffer | ArrayBuffer => #10744 (comment)) and after this to attach a constraint to the data => D | string | Buffer | ArrayBuffer.

type of data must be equal to type of result of AxiosRequestTransformer (because data = fn.call(config, data...)!

I think the current typing is valid only for the first call to transformRequest, but if there is an array of them and the first one does, for example, convert an object to a string or to a Buffer, then the typings will not correspond to what will happen at runtime!

@jasonsaayman

@jasonsaayman
Copy link
Copy Markdown
Member

Thanks for digging into this. You're right, transformRequest and transformResponse are left-fold pipelines, so data: D is only honest for the first function in the chain. Once any transformer returns a serialised form (string, Buffer, FormData, whatever), the next one isn't looking at D anymore.

I don't think that invalidates the PR, though. It just means the generic has a narrower scope than a fully sound pipeline type would.

I added a JSDoc on both interfaces. It explains the pipeline semantics, calls out that D/T only describes the first call, warns that later stages may see a serialised form, and says when typing D is safe and when you need a runtime check.

@salisbury-espinosa
Copy link
Copy Markdown

salisbury-espinosa commented Apr 27, 2026

I don't think that invalidates the PR, though. It just means the generic has a narrower scope than a fully sound pipeline type would.

but this is precisely what makes this PR invalid!

It explains the pipeline semantics, calls out that D/T only describes the first call

I added a JSDoc on both interfaces. It explains the pipeline semantics, calls out that D/T only describes the first call, warns that later stages may see a serialised form

But the interface and the code itself don't distinguish between the first call and subsequent calls.
This feels like workaround...
This should be in the typescript constraints, not in the documentation.

then it makes sense to simply not provide the API in order to create more than 1 transform request (but then backward compatibility will be lost)...

and says when typing D is safe and when you need a runtime check.

It turns out that the typings needed for compile-time do not describe what happens at runtime.
then the whole meaning is lost from the using of typescript....

@jasonsaayman
Copy link
Copy Markdown
Member

Fair, I agree that is true. I will revert this one as agreed we gain nothing really from this.

@jasonsaayman
Copy link
Copy Markdown
Member

Reverted in #10810

@salisbury-espinosa
Copy link
Copy Markdown

we gain nothing really from this.

From typings we get a well documented and type-safety API, this is valuable!
It's just a different type there (not D ==> I think most likely that D | string | Buffer | ArrayBuffer)

@salisbury-espinosa
Copy link
Copy Markdown

salisbury-espinosa commented Apr 27, 2026

Fair, I agree that is true. I will revert this one as agreed we gain nothing really from this.

@jasonsaayman We can make typing improvements that will match what happens at runtime like this (while maintaining backward compatibility):

https://github.com/axios/axios/blob/v1.x/lib/adapters/http.js#L574

interface AxiosRequestTransformer {
    (this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
  }


interface AxiosRequestConfig<D = any> {
    transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[];

======>

interface FirstAxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D, headers: AxiosRequestHeaders): D | Stream | string | Buffer | ArrayBuffer;
  }
interface AxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D | Stream | string | Buffer | ArrayBuffer, headers: AxiosRequestHeaders): D |  Stream | string | Buffer | ArrayBuffer;
  }
  
  
  
interface AxiosRequestConfig<D = any> {
    transformRequest?: FirstAxiosRequestTransformer | [FirstAxiosRequestTransformer, ...AxiosRequestTransformer[]];

jasonsaayman added a commit that referenced this pull request Apr 27, 2026
* Revert "chore: added clarifying docs for the type change (#10804)"

This reverts commit 25387ae.

* Revert "fix: transformRequest input typing (#10745)"

This reverts commit 694f1ec.
@salisbury-espinosa
Copy link
Copy Markdown

by the way @jasonsaayman

import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://github.com/',
  transformRequest: [
    function (data, headers) {
      return {};
    },
  ],
});

instance.post('/', {});

===>

failed because https://github.com/axios/axios/blob/v1.x/lib/adapters/http.js#L574 ==>

new AxiosError(
              'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream',
              AxiosError.ERR_BAD_REQUEST,
              config
            )

Am I correct in understanding that the results of chain calls transformRequest must be always Stream | string | Buffer | ArrayBuffer
then we need to improve the constraints here

==>

type ResultOfChainAxiosRequestTransformer = Stream | string | Buffer | ArrayBuffer;

interface FirstAndOnlyAxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D, headers: AxiosRequestHeaders):  ResultOfChainAxiosRequestTransformer;
  }
  
  
  
interface FirstOfChainAxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D, headers: AxiosRequestHeaders): D | ResultOfChainAxiosRequestTransformer;
  }
  
  
interface NotLastOfChainAxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D | ResultOfChainAxiosRequestTransformer, headers: AxiosRequestHeaders): D | ResultOfChainAxiosRequestTransformer;
  }
  
interface LastOfChainAxiosRequestTransformer<D> {
    (this: InternalAxiosRequestConfig, data: D | ResultOfChainAxiosRequestTransformer, headers: AxiosRequestHeaders):  ResultOfChainAxiosRequestTransformer;
  }
  
  
interface AxiosRequestConfig<D = any> {
    transformRequest?: FirstAndOnlyAxiosRequestTransformer | [FirstOfChainAxiosRequestTransformer, ...NotLastOfChainAxiosRequestTransformer[], LastOfChainAxiosRequestTransformer];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

proposal: improving typings of AxiosRequestTransformer

3 participants