如何用TypeBox创建支持运行时动态范围验证的自定义Schema
问题描述
我们有如下TypeScript接口:
interface RangedNumber { value: number; minValue: number; maxValue: number; }
可通过以下TypeBox Schema生成对应类型:
const Schema = Type.Object({ value: Type.Number(), minValue: Type.Number(), maxValue: Type.Number(), }); type RangeNumber = Static<typeof Schema>;
但该Schema仅能验证各属性的类型。已知可向Type.Number()传入minimum和maximum参数:
value: Type.Number({ minimum: x, maximum: y }),
但minValue和maxValue的具体值仅在运行时可知。现需创建符合要求的自定义TypeBox Schema,使得如下示例可通过验证:
{ value: 5, minValue: 0, maxValue: 10, }
而如下示例无法通过验证:
{ value: 200, minValue: 0, maxValue: 10, }
请问最优实现方案是什么?
最优实现方案
使用Type.Refine添加跨字段验证
TypeBox的Type.Refine方法可以在基础类型之上添加自定义断言逻辑,完美适配这种需要根据对象内部其他字段值做验证的场景。
实现代码如下:
import { Type, Static } from '@sinclair/typebox'; // 定义基础对象结构 const BaseRangedNumberSchema = Type.Object({ value: Type.Number(), minValue: Type.Number(), maxValue: Type.Number(), }); // 扩展添加跨字段验证 const RangedNumberSchema = Type.Refine(BaseRangedNumberSchema, (data) => { return data.value >= data.minValue && data.value <= data.maxValue; }, { message: 'value必须介于minValue和maxValue之间' }); // 生成TypeScript类型 type RangedNumber = Static<typeof RangedNumberSchema>;
验证效果
配合Ajv(TypeBox常用的验证引擎)使用:
import Ajv from 'ajv'; const ajv = new Ajv(); const validate = ajv.compile(RangedNumberSchema); // 合法数据验证通过 console.log(validate({ value: 5, minValue: 0, maxValue: 10 })); // true // 非法数据验证失败 console.log(validate({ value: 200, minValue: 0, maxValue: 10 })); // false console.log(validate.errors); // 输出自定义错误信息
方案优势
- 类型安全:生成的
RangedNumber类型完全继承原接口的类型定义,保留TypeScript静态类型检查能力。 - 运行时可靠:跨字段验证逻辑在运行时生效,精准拦截不符合规则的数据。
- 实现简洁:基于基础类型扩展,无需复杂的自定义关键字或额外工具链。
内容的提问来源于stack exchange,提问作者ThdK
相关产品推荐
相关产品推荐

