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

如何扩展Joi的number()校验规则支持带$符号的数字字符串

问题解答

完全可以在schema定义层面实现适配,不需要在调用validate前提前清洗数据,有两种常用实现方案按需选择:

方案1:轻量组合规则(无需扩展Joi)

不需要修改Joi原生逻辑,直接组合现有校验规则,就能实现带$前缀数值的校验,效果和原生Joi.number()完全一致:

// 支持$前缀的数值校验schema
const dollarNumSchema = Joi.string()
  // 校验格式:允许开头带$,后面是合法数字格式
  .pattern(/^\$?\d+(\.\d+)?$/, 'valid numeric value with optional $ prefix')
  .replace(/^\$/, '') // 校验通过后自动移除开头的$
  .cast('number') // 自动转换为数字类型,输出和原生number()校验无差异
  .options({ convert: true })

// 测试用例
dollarNumSchema.validate("$12.34") // 校验通过,返回值为12.34
dollarNumSchema.validate("12.34")  // 校验通过,返回值为12.34
dollarNumSchema.validate("$abc")   // 正常返回格式错误

这个方案写起来简单,适合单一场景使用,后续还可以链式调用min()、max()、precision()等所有数字校验规则,不会有兼容问题。

方案2:扩展原生number类型(适合全局复用)

如果想直接沿用Joi.number()的调用习惯,不需要每次都写字符串组合规则,可以通过Joi的扩展能力,给原生number类型增加$前缀的自动识别逻辑:

const Joi = require('joi');

// 扩展number类型,自动处理$前缀
const CustomJoi = Joi.extend(joi => ({
  type: 'number',
  base: joi.number(),
  coerce: {
    from: 'string',
    method(value) {
      // 输入为带$的字符串时,先移除$再走原生数字校验逻辑
      if (typeof value === 'string' && value.trim().startsWith('$')) {
        return { value: value.trim().slice(1) }
      }
      return value
    }
  }
}))

// 直接调用number()即可支持带$的字符串
CustomJoi.number().validate("$12.34") // 校验通过,返回值12.34
CustomJoi.number().validate("12.34")  // 原有逻辑不受影响,正常通过
CustomJoi.number().min(0).validate("$-12") // 正常触发最小值校验报错

扩展后的number类型完全保留原生所有校验能力,原有业务代码里的number规则不需要修改,只要替换成扩展后的Joi实例就能全局支持$前缀的数值输入。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:12:22