diff --git a/.changeset/red-toes-reflect.md b/.changeset/red-toes-reflect.md new file mode 100644 index 000000000..11d2fe399 --- /dev/null +++ b/.changeset/red-toes-reflect.md @@ -0,0 +1,5 @@ +--- +'@hono/zod-openapi': patch +--- + +infer env type parameter from middleware diff --git a/packages/zod-openapi/src/index.ts b/packages/zod-openapi/src/index.ts index 2af11c43b..9b96cf7f5 100644 --- a/packages/zod-openapi/src/index.ts +++ b/packages/zod-openapi/src/index.ts @@ -269,9 +269,17 @@ export type MiddlewareToHandlerType[] ? Last // Return the last remaining handler in the array : never +type RouteMiddlewareParams = OfHandlerType< + MiddlewareToHandlerType> +> + +export type RouteConfigToEnv = RouteMiddlewareParams extends never + ? Env + : RouteMiddlewareParams['env'] + export type RouteHandler< R extends RouteConfig, - E extends Env = Env, + E extends Env = RouteConfigToEnv, I extends Input = InputTypeParam & InputTypeQuery & InputTypeHeader & @@ -299,7 +307,7 @@ export type RouteHandler< export type RouteHook< R extends RouteConfig, - E extends Env = Env, + E extends Env = RouteConfigToEnv, I extends Input = InputTypeParam & InputTypeQuery & InputTypeHeader & @@ -381,7 +389,7 @@ export class OpenAPIHono< handler: Handler< // use the env from the middleware if it's defined R['middleware'] extends MiddlewareHandler[] | MiddlewareHandler - ? OfHandlerType>>['env'] & E + ? RouteMiddlewareParams['env'] & E : E, P, I, diff --git a/packages/zod-openapi/test/handler.test-d.ts b/packages/zod-openapi/test/handler.test-d.ts index daf0e4c43..384e9cf67 100644 --- a/packages/zod-openapi/test/handler.test-d.ts +++ b/packages/zod-openapi/test/handler.test-d.ts @@ -1,3 +1,4 @@ +import type { MiddlewareHandler } from 'hono' import type { RouteHandler } from '../src' import { OpenAPIHono, createRoute, z } from '../src' @@ -52,4 +53,40 @@ describe('supports async handler', () => { hono.openapi(route, handler) hono.openapi(route, asyncHandler) }) + + test('RouteHandler infers env type from middleware', () => { + type CustomEnv = { Variables: { customKey: string } } + + const customMiddleware: MiddlewareHandler = (c, next) => { + c.set('customKey', 'customValue') + return next() + } + + const routeWithMiddleware = createRoute({ + method: 'get', + path: '/users', + middleware: [customMiddleware] as const, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ + id: z.string(), + }), + }, + }, + description: 'Retrieve the user', + }, + }, + }) + + const handler: RouteHandler = (c) => { + return c.json({ + id: c.get('customKey'), + }) + } + + const hono = new OpenAPIHono() + hono.openapi(routeWithMiddleware, handler) + }) })