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

如何为Joi扩展带参数的splitArray类型实现链式配置split分隔符

实现方案

这个需求可以完全实现,核心思路是把分隔符配置存储在Schema实例本身,而非依赖校验阶段传入的全局配置。Joi扩展原生支持自定义链式方法、实例级配置存储,不需要额外hack。

完整扩展代码

const JoiBase = require('joi');

const splitArrayExt = joi => ({
  base: joi.array(),
  type: 'splitArray',
  // 定义Schema实例级别的配置项
  flags: {
    separator: {
      default: /\s+/ // 未指定分隔符时默认按任意空白字符拆分
    }
  },
  // 类型转换逻辑:字符串转数组
  coerce: (value, helpers) => {
    if (typeof value !== 'string') return { value };
    // 直接从当前Schema读取预先配置的分隔符
    const separator = helpers.schema.$_getFlag('separator');
    return { value: value.split(separator) };
  },
  // 自定义链式方法
  rules: {
    splitBy: {
      method(separator) {
        // 校验分隔符参数合法性
        if (typeof separator !== 'string' && !(separator instanceof RegExp)) {
          throw new TypeError('splitBy仅支持传入字符串或正则表达式作为分隔符');
        }
        // 将分隔符写入当前Schema实例的配置,返回新实例支持链式调用
        return this.$_setFlag('separator', separator);
      }
    }
  }
});

const Joi = JoiBase.extend(splitArrayExt);

效果验证

你预期的调用逻辑可以直接运行,结果完全符合要求:

const schema1 = Joi.splitArray().splitBy('|').items(Joi.string());
const schema2 = Joi.splitArray().splitBy(',').items(Joi.string());

console.log(schema1.validate('A|B,C').value); // [ 'A', 'B,C' ]
console.log(schema2.validate('A|B,C').value); // [ 'A|B', 'C' ]

// 未调用splitBy时走默认分隔符规则
const defaultSchema = Joi.splitArray().items(Joi.string());
console.log(defaultSchema.validate('hello world joi').value); // [ 'hello', 'world', 'joi' ]

核心逻辑说明

  • 用扩展配置里的flags字段存储Schema实例的独立配置,不同Schema实例的配置完全隔离,不会互相干扰
  • 自定义splitBy规则通过Joi内置的$_setFlag方法把分隔符写入当前实例,天然支持链式调用
  • coerce阶段通过helpers.schema拿到当前执行校验的Schema实例,通过$_getFlag读取预存的分隔符,不需要在validate调用时传入任何额外配置
  • 非字符串输入会直接跳过拆分逻辑,交给基础的数组类型规则处理,和Joi原生数组的校验行为保持一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:27:40