Skip to content

Commit 15f4edc

Browse files
TakehiroTadaclaude
andcommitted
feat: update examples for hey-api 0.92.3 and fix codegen bugs
- Generate backward-compatible services.gen.ts shim (re-exports from client.gen and sdk.gen) so existing import paths continue to work - Fix missing error type references: fall back to `unknown` when ${methodName}Error type does not exist in generated types - Fix incorrect `= {}` default for required SDK parameters by checking parameter optionality directly instead of extracting type properties - Add @hey-api/client-fetch to nextjs-app and tanstack-router-app - Add target: es2017 to nextjs-app tsconfig for iterator support - Remove stale @hey-api/client-fetch import from react-app App.tsx - Update test snapshots Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 333b762 commit 15f4edc

File tree

11 files changed

+99
-73
lines changed

11 files changed

+99
-73
lines changed

examples/nextjs-app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"test:generated": "tsc -p ./tsconfig.json --noEmit"
1414
},
1515
"dependencies": {
16+
"@hey-api/client-fetch": "^0.6.0",
1617
"@tanstack/react-query": "^5.59.13",
1718
"@tanstack/react-query-devtools": "^5.32.1",
1819
"next": "^14.2.3",

examples/nextjs-app/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"compilerOptions": {
3+
"target": "es2017",
34
"lib": ["dom", "dom.iterable", "esnext"],
45
"allowJs": true,
56
"skipLibCheck": true,

examples/react-app/src/App.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import "./App.css";
22
import { useState } from "react";
33

4-
import { createClient } from "@hey-api/client-fetch";
54
import {
65
UseFindPetsKeyFn,
76
useAddPet,
@@ -13,8 +12,6 @@ import { SuspenseParent } from "./components/SuspenseParent";
1312
import { queryClient } from "./queryClient";
1413

1514
function App() {
16-
createClient({ baseUrl: "http://localhost:4010" });
17-
1815
const [tags, _setTags] = useState<string[]>([]);
1916
const [limit, _setLimit] = useState<number>(10);
2017

examples/tanstack-router-app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"vite": "^5.4.4"
2525
},
2626
"dependencies": {
27+
"@hey-api/client-fetch": "^0.6.0",
2728
"@tanstack/react-query": "^5.59.13",
2829
"@tanstack/react-query-devtools": "^5.32.1",
2930
"@tanstack/react-router": "^1.58.7",

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common.mts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -329,25 +329,16 @@ export function getRequestParamFromMethod(
329329
pageParam?: string,
330330
modelNames: string[] = [],
331331
) {
332-
if (!getVariableArrowFunctionParameters(method).length) {
332+
const sdkParams = getVariableArrowFunctionParameters(method);
333+
if (!sdkParams.length) {
333334
return null;
334335
}
335336
const methodName = getNameFromVariable(method);
336337

337-
const params = getVariableArrowFunctionParameters(method).flatMap((param) => {
338-
const paramNodes = extractPropertiesFromObjectParam(param);
339-
340-
return paramNodes
341-
.filter((p) => p.name !== pageParam)
342-
.map((refParam) => ({
343-
name: refParam.name,
344-
// TODO: Client<Request, Response, unknown, RequestOptions> -> Client<Request, Response, unknown>
345-
typeName: getShortType(refParam.type?.getText() ?? ""),
346-
optional: refParam.optional,
347-
}));
348-
});
349-
350-
const areAllPropertiesOptional = params.every((param) => param.optional);
338+
// Use the SDK function's parameter optionality as the authoritative check.
339+
// Generic types like Options<XData, ThrowOnError> may not resolve correctly
340+
// via extractPropertiesFromObjectParam for type alias properties (path, url).
341+
const areAllPropertiesOptional = sdkParams[0].isOptional();
351342

352343
return ts.factory.createParameterDeclaration(
353344
undefined,

src/createUseMutation.mts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,30 @@ export const createUseMutation = ({
7676

7777
// @hey-api/client-axios -> `TError = AxiosError<AddPetError>`
7878
// @hey-api/client-fetch -> `TError = AddPetError`
79+
const errorTypeName = `${capitalizeFirstLetter(methodName)}Error`;
80+
const hasErrorType = modelNames.includes(errorTypeName);
81+
7982
const responseErrorType = ts.factory.createTypeParameterDeclaration(
8083
undefined,
8184
TError,
8285
undefined,
83-
client === "@hey-api/client-axios"
84-
? ts.factory.createTypeReferenceNode(
85-
ts.factory.createIdentifier("AxiosError"),
86-
[
87-
ts.factory.createTypeReferenceNode(
88-
ts.factory.createIdentifier(
89-
`${capitalizeFirstLetter(methodName)}Error`,
86+
hasErrorType
87+
? client === "@hey-api/client-axios"
88+
? ts.factory.createTypeReferenceNode(
89+
ts.factory.createIdentifier("AxiosError"),
90+
[
91+
ts.factory.createTypeReferenceNode(
92+
ts.factory.createIdentifier(errorTypeName),
9093
),
91-
),
92-
],
93-
)
94-
: ts.factory.createTypeReferenceNode(
95-
`${capitalizeFirstLetter(methodName)}Error`,
96-
),
94+
],
95+
)
96+
: ts.factory.createTypeReferenceNode(errorTypeName)
97+
: client === "@hey-api/client-axios"
98+
? ts.factory.createTypeReferenceNode(
99+
ts.factory.createIdentifier("AxiosError"),
100+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)],
101+
)
102+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
97103
);
98104

99105
const methodParameters =

src/createUseQuery.mts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import { addJSDocToNode } from "./util.mjs";
2222
const createApiResponseType = ({
2323
methodName,
2424
client,
25+
modelNames,
2526
}: {
2627
methodName: string;
2728
client: LimitedUserConfig["client"];
29+
modelNames: string[];
2830
}) => {
2931
/** Awaited<ReturnType<typeof myClass.myMethod>> */
3032
const awaitedResponseDataType = ts.factory.createIndexedAccessTypeNode(
@@ -75,24 +77,30 @@ const createApiResponseType = ({
7577
),
7678
);
7779

80+
const errorTypeName = `${capitalizeFirstLetter(methodName)}Error`;
81+
const hasErrorType = modelNames.includes(errorTypeName);
82+
7883
const responseErrorType = ts.factory.createTypeParameterDeclaration(
7984
undefined,
8085
TError.text,
8186
undefined,
82-
client === "@hey-api/client-axios"
83-
? ts.factory.createTypeReferenceNode(
84-
ts.factory.createIdentifier("AxiosError"),
85-
[
86-
ts.factory.createTypeReferenceNode(
87-
ts.factory.createIdentifier(
88-
`${capitalizeFirstLetter(methodName)}Error`,
87+
hasErrorType
88+
? client === "@hey-api/client-axios"
89+
? ts.factory.createTypeReferenceNode(
90+
ts.factory.createIdentifier("AxiosError"),
91+
[
92+
ts.factory.createTypeReferenceNode(
93+
ts.factory.createIdentifier(errorTypeName),
8994
),
90-
),
91-
],
92-
)
93-
: ts.factory.createTypeReferenceNode(
94-
`${capitalizeFirstLetter(methodName)}Error`,
95-
),
95+
],
96+
)
97+
: ts.factory.createTypeReferenceNode(errorTypeName)
98+
: client === "@hey-api/client-axios"
99+
? ts.factory.createTypeReferenceNode(
100+
ts.factory.createIdentifier("AxiosError"),
101+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)],
102+
)
103+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
96104
);
97105

98106
return {
@@ -501,6 +509,7 @@ export const createUseQuery = ({
501509
} = createApiResponseType({
502510
methodName,
503511
client,
512+
modelNames,
504513
});
505514

506515
const requestParam = getRequestParamFromMethod(method, undefined, modelNames);

src/generate.mts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { writeFile } from "node:fs/promises";
2+
import path from "node:path";
13
import { type UserConfig, createClient } from "@hey-api/openapi-ts";
24
import type { LimitedUserConfig } from "./cli.mjs";
35
import {
@@ -31,6 +33,12 @@ export async function generate(options: LimitedUserConfig, version: string) {
3133
plugins,
3234
};
3335
await createClient(config);
36+
37+
// Generate backward-compatible services.gen.ts shim
38+
// client.gen.ts has the `client` instance; sdk.gen.ts has SDK functions
39+
const shimContent = `// This file is auto-generated for backward compatibility\nexport * from './client.gen';\nexport * from './sdk.gen';\n`;
40+
await writeFile(path.join(openApiOutputPath, "services.gen.ts"), shimContent);
41+
3442
const source = await createSource({
3543
outputPath: openApiOutputPath,
3644
client: formattedOptions.client,

0 commit comments

Comments
 (0)