Skip to content

Commit 93584d1

Browse files
MathiasWPclaude
andauthored
fix: use Promise<Response> for async kit handler return types (#2966)
* fix: use Promise<Response> return type for async kit handlers When svelte-check adds type annotations to SvelteKit route handlers (GET, POST, etc.), it was using `Response | Promise<Response>` as the return type for all functions regardless of whether they were async. TypeScript requires async functions to return `Promise<T>`, not `T | Promise<T>` (TS1064). This caused false positives in `--incremental` mode where tsc runs on the generated files directly. The fix checks if the function has an async modifier and, if so, extracts just the `Promise<Response>` part of the return type union. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: format sveltekit.ts with prettier Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix async kit handler return types Updated async kit handler return types to use Promise<Response>. * style: format changeset Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: use asyncReturnType parameter instead of string splitting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e7168a9 commit 93584d1

File tree

5 files changed

+37
-4
lines changed

5 files changed

+37
-4
lines changed

.changeset/forty-tools-cheat.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'svelte-check': patch
3+
'svelte2tsx': patch
4+
---
5+
6+
fix: use Promise<Response> for async kit handler return types
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
export type PageData = {};
2+
export type RequestEvent = {
3+
url: URL;
4+
request: Request;
5+
params: Record<string, string>;
6+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export async function GET({ url }) {
2+
return new Response(url.pathname);
3+
}
4+
5+
export async function POST({ request }) {
6+
const body = await request.text();
7+
return new Response(body, { status: 201 });
8+
}

packages/svelte2tsx/src/helpers/sveltekit.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ function upsertKitRouteFile(
283283
isTsFile,
284284
name,
285285
`import('./$types.js').RequestEvent`,
286-
`Response | Promise<Response>`
286+
`Response | Promise<Response>`,
287+
`Promise<Response>`
287288
);
288289
};
289290
insertApiMethod('GET');
@@ -476,7 +477,8 @@ function addTypeToFunction(
476477
isTsFile: boolean,
477478
name: string,
478479
type: string,
479-
returnType?: string
480+
returnType?: string,
481+
asyncReturnType?: string
480482
) {
481483
const fn = exports.get(name);
482484
if (fn?.type === 'function' && fn.node.parameters.length === 1 && !fn.hasTypeDefinition) {
@@ -485,11 +487,15 @@ function addTypeToFunction(
485487
const paramInsertion = surround(!returnType ? `: Parameters<${type}>[0]` : `: ${type}`);
486488
insert(paramPos, paramInsertion);
487489
if (!fn.node.type && fn.node.body) {
490+
const isAsync =
491+
fn.node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
492+
const effectiveReturnType =
493+
isAsync && asyncReturnType ? asyncReturnType : returnType;
488494
const returnPos = ts.isArrowFunction(fn.node)
489495
? fn.node.equalsGreaterThanToken.getStart()
490496
: fn.node.body.getStart();
491497
const returnInsertion = surround(
492-
!returnType ? `: ReturnType<${type}> ` : `: ${returnType} `
498+
!effectiveReturnType ? `: ReturnType<${type}> ` : `: ${effectiveReturnType} `
493499
);
494500
insert(returnPos, returnInsertion);
495501
}

packages/svelte2tsx/test/helpers/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,15 @@ describe('Internal Helpers - upsertKitFile', () => {
7171
upsert(
7272
'+server.ts',
7373
`export async function GET(e) {}`,
74-
`export async function GET(e: import('./$types.js').RequestEvent) : Response | Promise<Response> {}`
74+
`export async function GET(e: import('./$types.js').RequestEvent) : Promise<Response> {}`
75+
);
76+
});
77+
78+
it('upserts GET non-async function', () => {
79+
upsert(
80+
'+server.ts',
81+
`export function GET(e) { return new Response(); }`,
82+
`export function GET(e: import('./$types.js').RequestEvent) : Response | Promise<Response> { return new Response(); }`
7583
);
7684
});
7785

0 commit comments

Comments
 (0)