fix(aws-lambda): infer response type from event via overloads#4872
fix(aws-lambda): infer response type from event via overloads#4872Danny-Devs wants to merge 2 commits intohonojs:mainfrom
Conversation
The handle() return type used a conditional
L extends { multiValueHeaders: Record<string, string[]> } that
was vacuous — every LambdaEvent member declares the field as
optional (v1, ALB) or omits/undefines it (v2, Lattice), so the
conditional always resolved to the WithHeaders branch regardless
of the input event type. A @ts-expect-error FIXME hid the
mismatch between the declared return type and the actual value
returned by processor.createResult.
Replace with per-event overloads that fulfill the "Infer response
type from event" intent from 0e4dfe5: v2 and Lattice narrow to
APIGatewayProxyResult & WithHeaders (runtime cannot produce the
multi-value branch for them); v1 and ALB return the full union.
The overload pattern matches HonoRequest.param in src/request.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4872 +/- ##
=======================================
Coverage 92.89% 92.89%
=======================================
Files 177 177
Lines 11797 11801 +4
Branches 3515 3514 -1
=======================================
+ Hits 10959 10963 +4
Misses 837 837
Partials 1 1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…sence Refine LambdaHandlerFunction overloads so the return type reflects the runtime's multiValueHeaders decision: - Event with multiValueHeaders present → WithMultiValueHeaders - Event with multiValueHeaders absent → WithHeaders - Generic LambdaEvent (unknown) → full union This eliminates 12 TS18048 errors in the runtime-tests without any test changes — the type system now models the exact runtime behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The "Type & Bundle size Check on PR" failed on the first push — This was the original overloads being correct but imprecise: v1/ALB returned the full Rather than adding non-null assertions to the test file, I refined the overloads to also narrow based on |
|
It's good to remove |
Summary
While reviewing the AWS Lambda adapter, I noticed
handle()used a conditional return type guarded by@ts-expect-error FIXME: Fix return typing. Tracing the FIXME back to commit 0e4dfe5 (#3883), the author's goal was to "Infer response type from event" — narrowing toWithHeadersfor events that cannot produce multi-value headers.The issue
The conditional
L extends { multiValueHeaders: Record<string, string[]> } ? WithMultiValueHeaders : WithHeadersis vacuous. EveryLambdaEventmember declaresmultiValueHeadersas optional (v1, ALB) or omits/undefines it (v2 which has?: undefined, Lattice which has no such field), so none satisfy the required-field extends constraint. The conditional always resolves toWithHeadersregardless of the input event type, and the@ts-expect-erroron the implementation hides the mismatch between the declared return type and the actual value produced byprocessor.createResult(which at runtime may return either branch, based on'multiValueHeaders' in event && event.multiValueHeaders).The fix
Replace the conditional with per-event overloads that encode the real runtime guarantee. The overloads are ordered for resolution:
APIGatewayProxyResult & WithHeaders— these event types never produce multi-value headersmultiValueHeaderspresent →APIGatewayProxyResult & WithMultiValueHeaders— the runtime uses multi-value headers when the event carries themmultiValueHeadersabsent/undefined →APIGatewayProxyResult & WithHeaders— the runtime uses regular headers otherwiseLambdaEventfallback → the fullAPIGatewayProxyResultunion — for callers whose event type is not statically knownThis models the exact runtime behavior of
getProcessorandcreateResult, so callers get the most precise return type the type system can express from their call-site argument.The overload pattern matches
HonoRequest.paraminsrc/request.ts:94-104. Theas LambdaHandlerFunctioncast is the idiomatic TypeScript pattern for giving aconstarrow function multiple call signatures — arrow functions cannot use stackedfunctiondeclaration overloads.No change in runtime behavior. The
@ts-expect-error FIXME: Fix return typingdirective is removed.Verification
bun tsc --build— clean (the runtime-tests/lambda test file compiles without changes, since the overloads are precise enough for TypeScript to infer the correct return type from each test's inline event literal)bun run test— 4255 passed, 33 skipped, 0 failedbun run build— green (includes declaration emission and publint)bun run format:fix && bun run lint:fix— no changes needed@ts-expect-error-style test file that imported the realhandlefrom this branch and asserted the narrowing contract for all four event types (v2/Lattice narrow toWithHeaderswithout a discriminant; v1/ALB correctly require one when multiValueHeaders presence is unknown). Happy to contribute that as a follow-up if the team would like a regression guard in the test suite — kept this PR focused on the fix itself.The author should do the following, if applicable
bun run format:fix && bun run lint:fixto format the code