Skip to content

Commit 1aa32fb

Browse files
authored
fix(types): infer response type from last handler in app.on 9- and 10-handler overloads (#4865)
The 9- and 10-handler `app.on` overloads declared `R` on the last handler position but discarded it, hardcoding `MergeTypedResponse<HandlerResponse<any>>` in the schema instead. This caused the inferred `output` to collapse to `{} | Promise<void>` regardless of what the response handler returned. Affected overloads: - app.on(method, path, handler x10) - app.on(method[], path, handler x9) - app.on(method[], path, handler x10) The 8-handler variants were already using `MergeTypedResponse<R>` correctly.
1 parent c37ba26 commit 1aa32fb

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

src/types.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,53 @@ describe('OnHandlerInterface', () => {
401401
}
402402
type verify = Expect<Equal<Expected, Actual>>
403403
})
404+
405+
test('app.on(method, path, ...10 handlers) - last handler response type should be inferred', () => {
406+
const noop: MiddlewareHandler = async (_c, next) => {
407+
await next()
408+
}
409+
const route = app.on('GET', '/x10', noop, noop, noop, noop, noop, noop, noop, noop, noop, (c) =>
410+
c.json({ success: true })
411+
)
412+
type Actual = ExtractSchema<typeof route>['/x10']['$get']['output']
413+
type Expected = { success: true }
414+
type verify = Expect<Equal<Expected, Actual>>
415+
})
416+
417+
test('app.on(method[], path, ...9 handlers) - last handler response type should be inferred', () => {
418+
const noop: MiddlewareHandler = async (_c, next) => {
419+
await next()
420+
}
421+
const route = app.on(['GET'], '/x9-arr', noop, noop, noop, noop, noop, noop, noop, noop, (c) =>
422+
c.json({ success: true })
423+
)
424+
type Actual = ExtractSchema<typeof route>['/x9-arr']['$get']['output']
425+
type Expected = { success: true }
426+
type verify = Expect<Equal<Expected, Actual>>
427+
})
428+
429+
test('app.on(method[], path, ...10 handlers) - last handler response type should be inferred', () => {
430+
const noop: MiddlewareHandler = async (_c, next) => {
431+
await next()
432+
}
433+
const route = app.on(
434+
['GET'],
435+
'/x10-arr',
436+
noop,
437+
noop,
438+
noop,
439+
noop,
440+
noop,
441+
noop,
442+
noop,
443+
noop,
444+
noop,
445+
(c) => c.json({ success: true })
446+
)
447+
type Actual = ExtractSchema<typeof route>['/x10-arr']['$get']['output']
448+
type Expected = { success: true }
449+
type verify = Expect<Equal<Expected, Actual>>
450+
})
404451
})
405452

406453
describe('TypedResponse', () => {

src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ export interface OnHandlerInterface<
17901790
]
17911791
): HonoBase<
17921792
IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>,
1793-
S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<HandlerResponse<any>>>,
1793+
S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<R>>,
17941794
BasePath,
17951795
MergePath<BasePath, P>
17961796
>
@@ -2095,7 +2095,7 @@ export interface OnHandlerInterface<
20952095
]
20962096
): HonoBase<
20972097
IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10]>,
2098-
S & ToSchema<M, MergePath<BasePath, P>, I9, MergeTypedResponse<HandlerResponse<any>>>,
2098+
S & ToSchema<M, MergePath<BasePath, P>, I9, MergeTypedResponse<R>>,
20992099
BasePath,
21002100
MergePath<BasePath, P>
21012101
>
@@ -2143,7 +2143,7 @@ export interface OnHandlerInterface<
21432143
]
21442144
): HonoBase<
21452145
IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11]>,
2146-
S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<HandlerResponse<any>>>,
2146+
S & ToSchema<M, MergePath<BasePath, P>, I10, MergeTypedResponse<R>>,
21472147
BasePath,
21482148
MergePath<BasePath, P>
21492149
>

0 commit comments

Comments
 (0)