You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hono Zod验证中间件时遭遇类型安全问题求助

Hono Zod验证中间件类型安全问题解决方案

问题场景

我在Hono中使用Zod和@hono/zod-validator实现验证中间件,代码如下:

const validationMiddleware = (schema: ZodSchema, target: keyof ValidationTargets) => {
    return createMiddleware(async (c, next) => {
        await next()
        zValidator(target, schema, (result, c) => {
            if (!result.success) {
                return c.json({
                    success: false,
                    error: {
                        code: 400,
                        message: result.error.issues[0].message,
                        innerError: {
                            timestamp: new Date(Date.now())
                        }
                    }
                })
            }
        })
    })
}

调用方式:

validationMiddleware(userValidation, 'json')

使用c.req.valid('json')时TypeScript抛出错误:

TS2345: Argument of type string is not assignable to parameter of type never on the 'json' input

TypeScript将参数类型推断为never,无法获得预期的类型安全支持。

问题根源

  1. 执行顺序错误:先调用await next()会让路由逻辑先于验证执行,不仅逻辑颠倒,还打断了Hono的类型推断链,导致框架无法识别该目标已被验证。
  2. 类型信息缺失:中间件没有通过泛型传递Zod Schema的类型信息,Hono无法关联验证目标和对应的类型。

修复方案

1. 修正中间件执行逻辑

先执行验证,验证通过后再进入后续路由/中间件:

import { createMiddleware } from 'hono'
import { zValidator } from '@hono/zod-validator'
import type { ZodSchema, ValidationTargets } from 'hono'

const validationMiddleware = <T extends ZodSchema>(
  schema: T,
  target: keyof ValidationTargets
) => {
  return createMiddleware(async (c, next) => {
    // 先执行验证逻辑,再推进到下一个环节
    await zValidator(target, schema, (result, c) => {
      if (!result.success) {
        return c.json({
          success: false,
          error: {
            code: 400,
            message: result.error.issues[0].message,
            innerError: {
              timestamp: new Date(Date.now())
            }
          }
        }, 400) // 显式指定400状态码更规范
      }
    })(c, next)
  })
}

2. 添加泛型捕获Schema类型

通过泛型<T extends ZodSchema>捕获传入的Schema类型,让Hono的类型系统能正确关联验证目标和对应的类型。

3. 验证类型安全效果

在路由中使用中间件后,c.req.valid('json')会自动推断出Schema对应的类型:

// 示例Zod Schema
import { z } from 'zod'
const userValidation = z.object({
  username: z.string().min(3),
  email: z.string().email()
})

// 路由中使用中间件
app.post('/users', validationMiddleware(userValidation, 'json'), (c) => {
  // 此处c.req.valid('json')类型自动推断为{ username: string; email: string }
  const validUser = c.req.valid('json')
  return c.json({ success: true, data: validUser })
})

内容的提问来源于stack exchange,提问作者hantoren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:05:53