fix(types): infer response type from last handler in app.on 9-/10-handler overloads#4865
Merged
yusukebe merged 1 commit intohonojs:mainfrom Apr 8, 2026
Conversation
…-handler overloads
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.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4865 +/- ##
=======================================
Coverage 92.89% 92.89%
=======================================
Files 177 177
Lines 11797 11797
Branches 3515 3514 -1
=======================================
Hits 10959 10959
Misses 837 837
Partials 1 1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Member
|
Hi @T4ko0522 The implementation and test are good. Thank you for your contribution! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The 9- and 10-handler overloads of
OnHandlerInterfacedeclared a type parameterRon the final handler position but discarded it from the schema computation, hardcodingMergeTypedResponse<HandlerResponse<any>>instead. As a result, the inferredoutputcollapses to{} | Promise<void>andoutputFormattostringregardless of what the response handler actually returns, so the RPC client resolvesr.json()asPromise<unknown>.This is a write-omission that was introduced in #1735 (2023-11) and carried through subsequent refactors without being noticed — the surrounding x1–x8 overloads are all using
MergeTypedResponse<R>correctly.Affected overloads
This affects only the x9 / x10 overloads of
OnHandlerInterface.The x1–x8 overloads already use
MergeTypedResponse<R>correctly.Reproduction
Reducing the chain to 8 handlers makes the inference work correctly even on
main, because the x8 overload is not affected by the bug. This bizarre cliff at the x9 boundary is the symptom.Fix
3-line change in
src/types.ts:Rwas already declared in the type parameter list and properly captured by the lastH<E11, MergedPath, I10, R>element of the handler tuple — only the schema computation was failing to use it.Test plan
Added 3 regression tests under
describe('OnHandlerInterface', ...)insrc/types.test.ts, one per fixed overload. Each test passes 9 or 10 handlers and asserts that the schema'soutputmatches the response handler's return type.These tests fail on
main(the schema'soutputis{} | Promise<void>) and pass after this fix.bun run format:fix && bun run lint:fixbun run test(full type check + vitest)Related history
This is not related to #3485 / the
.then()arrow-function inference issue, which is a separate TypeScript-level limitation inH = Handler | MiddlewareHandlerunion inference. This PR fixes an unrelated, mechanical write-omission.HandlerResponse<any>in the new x9 / x10 overloadsToSchema& WebSocket Helper types (#2588)MergeTypedResponseData→MergeTypedResponse, hardcode preservedMs[number]→M), hardcode preservedI am using a translation tool. I apologize if any of my expressions cause misunderstanding.