Skip to content

Commit

Permalink
fix(zod-openapi): multi-middleware complex type inference (#849)
Browse files Browse the repository at this point in the history
  • Loading branch information
askorupskyy authored Nov 28, 2024
1 parent 83cc764 commit 4ebecc6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-hairs-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hono/zod-openapi': patch
---

Fix multi-middleware complex object type inference
4 changes: 3 additions & 1 deletion packages/zod-openapi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ type AsArray<T> = T extends undefined // TODO move to utils?
*/
export type DeepSimplify<T> = {
// TODO move to utils?
[KeyType in keyof T]: T[KeyType] extends object ? DeepSimplify<T[KeyType]> : T[KeyType]
[KeyType in keyof T]: T[KeyType] extends Record<string, unknown>
? DeepSimplify<T[KeyType]>
: T[KeyType]
} & {}

/**
Expand Down
36 changes: 35 additions & 1 deletion packages/zod-openapi/test/handler.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { MiddlewareHandler } from 'hono'
import type { RouteHandler } from '../src'
import type { Equal, Expect } from 'hono/utils/types'
import type { MiddlewareToHandlerType, OfHandlerType, RouteHandler } from '../src'

import { OpenAPIHono, createRoute, z } from '../src'

describe('supports async handler', () => {
Expand Down Expand Up @@ -89,4 +91,36 @@ describe('supports async handler', () => {
const hono = new OpenAPIHono()
hono.openapi(routeWithMiddleware, handler)
})

test('RouteHandler infers complex objects from multiple middleware handlers', () => {
// https://github.com/honojs/middleware/issues/847
type CustomEnv = { Variables: { session: { id: string; createdAt: Date } } }

const setSessionMiddleware: MiddlewareHandler<CustomEnv> = (c, next) => {
c.set('session', { id: '8e760fe8-f064-4929-b632-737f88213e57', createdAt: new Date() })
return next()
}

const validateSessionMiddleware: MiddlewareHandler<CustomEnv> = async (c, next) => {
const session = c.get('session')
if ((new Date().getTime() - session.createdAt.getTime()) / 1000 / 60 / 60 > 1) {
return c.json({ message: 'Unauthorized' }, 401)
}
return await next()
}

type Example = MiddlewareToHandlerType<
[typeof setSessionMiddleware, typeof validateSessionMiddleware]
>

// ensure the first defined env does not lose its type in multi-middleware handler
type Verify = Expect<
Equal<
OfHandlerType<Example>['env'],
{
Variables: CustomEnv['Variables']
}
>
>
})
})

0 comments on commit 4ebecc6

Please sign in to comment.