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

如何使用Elysia的Typebox实现多校验规则自定义错误提示?

在Elysia中使用TypeBox为不同校验规则设置自定义错误提示

TypeBox本身的error属性仅支持单一错误消息,但可以通过自定义校验规则结合Elysia错误拦截器或手动校验的方式,实现类似Joi的多规则对应不同错误提示的效果。以下是两种可行的实现方案:

方案一:全局错误拦截器(推荐)

通过Elysia的onError钩子统一拦截验证错误,根据错误的code和path映射自定义消息,无需在每个路由重复处理逻辑。

完整代码示例

import { t, type Static, Elysia } from "elysia"

// 定义Schema,添加基础校验和自定义Refine规则
export const CreateUserSchema = t.Object({
  name: t.String({
    minLength: 1
  }).Refine((value) => value.trim() !== "", {
    message: "临时占位",
    code: "string.empty"
  }),
  email: t.String({
    format: "email"
  }).Refine((value) => value.trim() !== "", {
    message: "临时占位",
    code: "string.empty"
  }),
  password: t.String({
    minLength: 6
  }).Refine((value) => value.trim() !== "", {
    message: "临时占位",
    code: "string.empty"
  })
}, {
  // 标记必填字段,触发required错误
  required: ["name", "email", "password"]
})

export type CreateUserDTO = Static<typeof CreateUserSchema>

// 初始化Elysia并配置错误拦截
const app = new Elysia()
  .onError(({ error, code }) => {
    if (code === "VALIDATION") {
      const validationErrors = (error as any).errors
      return {
        status: 400,
        body: {
          errors: validationErrors.map((err: any) => {
            // 根据字段路径和错误code返回自定义消息
            switch (err.path) {
              case "/name":
                if (err.code === "required") return "The name field is required."
                if (err.code === "minLength") return "The name field is required."
                if (err.code === "string.empty") return "The name field cannot be empty."
                break
              case "/email":
                if (err.code === "required") return "The email field is required."
                if (err.code === "format") return "The email field is invalid."
                if (err.code === "string.empty") return "The email field cannot be empty."
                break
              case "/password":
                if (err.code === "required") return "The password field is required."
                if (err.code === "minLength") return "The password field must have at least 6 characters."
                if (err.code === "string.empty") return "The password field cannot be empty."
                break
            }
            return err.message
          })
        }
      }
    }
  })
  .post("/users", ({ body }) => body, {
    body: CreateUserSchema
  })
  .listen(3000)

方案二:手动校验(灵活定制)

使用TypeBox的TypeCompiler预编译Schema,在路由内手动执行校验并返回自定义错误,适合需要针对单个路由定制逻辑的场景。

完整代码示例

import { t, type Static, Elysia } from "elysia"
import { TypeCompiler } from "@sinclair/typebox/compiler"

export const CreateUserSchema = t.Object({
  name: t.String({
    minLength: 1
  }).Refine((value) => value.trim() !== "", {
    code: "string.empty"
  }),
  email: t.String({
    format: "email"
  }).Refine((value) => value.trim() !== "", {
    code: "string.empty"
  }),
  password: t.String({
    minLength: 6
  }).Refine((value) => value.trim() !== "", {
    code: "string.empty"
  })
}, {
  required: ["name", "email", "password"]
})

export type CreateUserDTO = Static<typeof CreateUserSchema>

// 预编译校验器
const CreateUserValidator = TypeCompiler.Compile(CreateUserSchema)

const app = new Elysia()
  .post("/users", ({ body, set }) => {
    // 执行校验
    const isValid = CreateUserValidator.Check(body)
    if (!isValid) {
      const errors = CreateUserValidator.Errors(body)
      const customErrors: string[] = []

      for (const err of errors) {
        switch (err.path) {
          case "/name":
            if (err.code === "required") customErrors.push("The name field is required.")
            if (err.code === "minLength") customErrors.push("The name field is required.")
            if (err.code === "string.empty") customErrors.push("The name field cannot be empty.")
            break
          case "/email":
            if (err.code === "required") customErrors.push("The email field is required.")
            if (err.code === "format") customErrors.push("The email field is invalid.")
            if (err.code === "string.empty") customErrors.push("The email field cannot be empty.")
            break
          case "/password":
            if (err.code === "required") customErrors.push("The password field is required.")
            if (err.code === "minLength") customErrors.push("The password field must have at least 6 characters.")
            if (err.code === "string.empty") customErrors.push("The password field cannot be empty.")
            break
        }
      }

      set.status = 400
      return { errors: customErrors }
    }

    return body
  })
  .listen(3000)

关键说明

  1. 必填字段配置:通过t.Object的required属性标记必填字段,缺失时会触发required错误code。
  2. 自定义校验规则:使用t.Refine添加额外校验(如非空判断),并指定自定义code以便后续映射错误消息。
  3. 错误code对应关系:TypeBox内置校验的code包括:
    • required: 字段未提供
    • minLength: 字符串长度不足
    • format: 格式不符合(如email)
    • 自定义Refine规则可自行指定code

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:45:55