kubb-labs / kubb

The ultimate toolkit for working with APIs.
https://kubb.dev
MIT License
738 stars 67 forks source link

"Return type of exported function has or is using name 'RawAxiosHeaders' from external module {node_modules/axios/index} but cannot be named. " #1397

Open komali2 opened 1 week ago

komali2 commented 1 week ago

What version of kubb is running?

3.05

What platform is your computer?

linux

What version of external packages are you using(@tanstack-query, MSW, React, Vue, ...)

tanstack query: 5.51.23, react: 18,

What steps can reproduce the bug?

Integrate this into an openapi.json file:

    "/steps/{step_id}": {
      "delete": {
        "tags": [
          "Steps"
        ],
        "summary": "Flag a step as deleted",
        "operationId": "delete_step",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "step_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "title": "Step Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Step"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "field": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Steps"
        ],
        "summary": "Get a step",
        "operationId": "get_step",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "step_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "title": "Step Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Step"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "field": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Steps"
        ],
        "summary": "Update a step",
        "operationId": "update_step",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "step_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "title": "Step Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStep"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Step"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "field": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "field": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

Follow a config similar to this:

import { defineConfig } from "@kubb/core";
import { pluginTs } from "@kubb/plugin-ts";
import { pluginZod } from "@kubb/plugin-zod";
import { pluginReactQuery } from "@kubb/plugin-react-query";
import { pluginOas } from "@kubb/plugin-oas";

export default defineConfig({
  root: ".",
  input: {
    path: "./apps/backend/openapi.json",
  },
  output: {
    path: "./apps/webapp/src/gen",
    clean: true,
  },
  hooks: {
    done: ["npm run lintfix", "npm run format"],
  },
  plugins: [
    pluginOas(),
    pluginTs({
      output: {
        path: "models",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Controller`,
      },
      enumType: "literal",
    }),
    pluginZod({
      output: {
        path: "./zod",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Schemas`,
      },
      typed: true,
      dateType: "stringOffset",
      unknownType: "unknown",
      importPath: "zod",
    }),
    pluginReactQuery({
      output: {
        path: "./hooks",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Hooks`,
      },
      client: {
        dataReturnType: "full",
      },
      mutation: {
        methods: ["post", "put", "delete"],
      },
      infinite: {
        queryParam: "page",
        initialPageParam: 0,
        cursorParam: undefined,
      },
      query: {
        methods: ["get"],
        importPath: "@tanstack/react-query",
      },
      parser: "zod",
      pathParamsType: "object",
    }),
  ],
});

Generate.

In /src/gen/hooks/stepsHooks/useGetStep.ts, observe this typescript error:

 useGetStep.ts    44  17 error    4058   Return type of exported function has or is using name 'RawAxiosHeaders' from external module "/node_modules/axios/index" but cannot be named. (lsp)

On this function:

export function getStepQueryOptions(
  { step_id }: GetStepPathParams,
  config: Partial<RequestConfig> = {}
) {
  const queryKey = getStepQueryKey({ step_id });
  return queryOptions({
    enabled: !!step_id,
    queryKey,
    queryFn: async ({ signal }) => {
      config.signal = signal;
      return getStep({ step_id }, config);
    },
  });
}

How often does this bug happen?

Every time

What is the expected behavior?

No typescript errors :)

Swagger/OpenAPI file?

Shown above.

Additional information

No response

linear[bot] commented 1 week ago

KUBB-68 "Return type of exported function has or is using name 'RawAxiosHeaders' from external module {node_modules/axios/index} but cannot be named. "

komali2 commented 1 week ago

Possibly related: https://github.com/axios/axios/issues/6369

komali2 commented 1 week ago

Maintains as issue even if using custom client that uses fetch

export type RequestConfig<TData = unknown> = {
  url: string;
  method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE";
  params?: object;
  data?: TData | FormData;
  responseType?:
    | "arraybuffer"
    | "blob"
    | "document"
    | "json"
    | "text"
    | "stream";
  signal?: AbortSignal;
  headers?: HeadersInit;
};

export type ResponseConfig<TData = unknown> = {
  data: TData;
  status: number;
  statusText: string;
};

export const fetchClient = async <
  TData,
 _TError = unknown,
  TVariables = unknown,
>(
  config: RequestConfig<TVariables>,
): Promise<ResponseConfig<TData>> => {
  const response = await fetch(config.url, {
    method: config.method.toUpperCase(),
    body: JSON.stringify(config.data),
    signal: config.signal,
    headers: config.headers,
  });

  const data = await response.json();

  return {
    data,
    status: response.status,
    statusText: response.statusText,
  };
};

export default fetchClient;
stijnvanhulle commented 1 week ago

@komali2 can you try adding dom in your tsconfig.json

 "compilerOptions": {
    "lib": ["DOM", "DOM.Iterable", "ES2023"]
  },
komali2 commented 3 days ago

I added that, and it seems to fix the issue if I use a custom client, however the issue still remains if I don't use a custom client.

komali2 commented 3 days ago

I needed to update the example custom client to add OPTIONS as a possible method:

export type RequestConfig<TData = unknown> = {
  url: string;
  method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE" | "OPTIONS";
  params?: object;
  data?: TData | FormData;
  responseType?:
    | "arraybuffer"
    | "blob"
    | "document"
    | "json"
    | "text"
    | "stream";
  signal?: AbortSignal;
  headers?: HeadersInit;
};

export type ResponseConfig<TData = unknown> = {
  data: TData;
  status: number;
  statusText: string;
};

export const fetchClient = async <
  TData,
 _TError = unknown,
  TVariables = unknown,
>(
  config: RequestConfig<TVariables>,
): Promise<ResponseConfig<TData>> => {
  const response = await fetch(config.url, {
    method: config.method.toUpperCase(),
    body: JSON.stringify(config.data),
    signal: config.signal,
    headers: config.headers,
  });

  const data = await response.json();

  return {
    data,
    status: response.status,
    statusText: response.statusText,
  };
};

export default fetchClient;
komali2 commented 3 days ago

Also, though I included the custom client in my config file:

import { defineConfig } from "@kubb/core";
import { pluginTs } from "@kubb/plugin-ts";
import { pluginZod } from "@kubb/plugin-zod";
import { pluginReactQuery } from "@kubb/plugin-react-query";
import { pluginOas } from "@kubb/plugin-oas";
import { pluginClient } from "@kubb/plugin-client";

export default defineConfig({
  root: ".",
  input: {
    path: "./apps/backend/openapi.json",
  },
  output: {
    path: "./apps/webapp/src/gen",
    clean: true,
  },
  hooks: {
    done: ["npm run lintfix", "npm run format"],
  },
  plugins: [
    pluginOas(),
    pluginTs({
      output: {
        path: "models",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Controller`,
      },
      enumType: "literal",
    }),
    pluginClient({
      output: {
        path: ".",
      },
      importPath: "./kubb-client.ts",
    }),
    pluginZod({
      output: {
        path: "./zod",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Schemas`,
      },
      typed: true,
      dateType: "stringOffset",
      unknownType: "unknown",
      importPath: "zod",
    }),
    pluginReactQuery({
      output: {
        path: "./hooks",
      },
      group: {
        type: "tag",
        name: ({ group }) => `${group}Hooks`,
      },
      client: {
        dataReturnType: "full",
      },
      mutation: {
        methods: ["post", "put", "delete"],
      },
      infinite: {
        queryParam: "page",
        initialPageParam: 0,
        cursorParam: undefined,
      },
      query: {
        methods: ["get"],
        importPath: "@tanstack/react-query",
      },
      parser: "zod",
      pathParamsType: "object",
    }),
  ],
});

The generated files instead still point to the default client:

import client from "@kubb/plugin-client/client";
import type { GetStepQueryResponse, GetStepPathParams, GetStep400, GetStep401, GetStep403, GetStep404 } from "../../models/stepsController/GetStep.ts";
import type { RequestConfig, ResponseConfig } from "@kubb/plugin-client/client";

And I needed to manually change them to point to the custom client file.