Skip to content

Commit 4ebecc6

Browse files
authored
fix(zod-openapi): multi-middleware complex type inference (#849)
1 parent 83cc764 commit 4ebecc6

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

.changeset/stale-hairs-wonder.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hono/zod-openapi': patch
3+
---
4+
5+
Fix multi-middleware complex object type inference

packages/zod-openapi/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ type AsArray<T> = T extends undefined // TODO move to utils?
221221
*/
222222
export type DeepSimplify<T> = {
223223
// TODO move to utils?
224-
[KeyType in keyof T]: T[KeyType] extends object ? DeepSimplify<T[KeyType]> : T[KeyType]
224+
[KeyType in keyof T]: T[KeyType] extends Record<string, unknown>
225+
? DeepSimplify<T[KeyType]>
226+
: T[KeyType]
225227
} & {}
226228

227229
/**

packages/zod-openapi/test/handler.test-d.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { MiddlewareHandler } from 'hono'
2-
import type { RouteHandler } from '../src'
2+
import type { Equal, Expect } from 'hono/utils/types'
3+
import type { MiddlewareToHandlerType, OfHandlerType, RouteHandler } from '../src'
4+
35
import { OpenAPIHono, createRoute, z } from '../src'
46

57
describe('supports async handler', () => {
@@ -89,4 +91,36 @@ describe('supports async handler', () => {
8991
const hono = new OpenAPIHono()
9092
hono.openapi(routeWithMiddleware, handler)
9193
})
94+
95+
test('RouteHandler infers complex objects from multiple middleware handlers', () => {
96+
// https://github.com/honojs/middleware/issues/847
97+
type CustomEnv = { Variables: { session: { id: string; createdAt: Date } } }
98+
99+
const setSessionMiddleware: MiddlewareHandler<CustomEnv> = (c, next) => {
100+
c.set('session', { id: '8e760fe8-f064-4929-b632-737f88213e57', createdAt: new Date() })
101+
return next()
102+
}
103+
104+
const validateSessionMiddleware: MiddlewareHandler<CustomEnv> = async (c, next) => {
105+
const session = c.get('session')
106+
if ((new Date().getTime() - session.createdAt.getTime()) / 1000 / 60 / 60 > 1) {
107+
return c.json({ message: 'Unauthorized' }, 401)
108+
}
109+
return await next()
110+
}
111+
112+
type Example = MiddlewareToHandlerType<
113+
[typeof setSessionMiddleware, typeof validateSessionMiddleware]
114+
>
115+
116+
// ensure the first defined env does not lose its type in multi-middleware handler
117+
type Verify = Expect<
118+
Equal<
119+
OfHandlerType<Example>['env'],
120+
{
121+
Variables: CustomEnv['Variables']
122+
}
123+
>
124+
>
125+
})
92126
})

0 commit comments

Comments
 (0)