如何使用io-ts实现API请求对象的严格属性校验?
使用io-ts实现API输入的严格校验(禁止未声明属性)
问题背景
我正在使用io-ts进行API输入校验,需要确保请求对象中不存在未声明的属性。
定义的请求接口如下:
const Request = t.type({ id: t.string, name: t.string });
测试输入内容:
const req = { id: 'r1', name: 'req 1', description: 'desc' // 该属性未在Request类型中声明 }
执行校验代码:
const r = Request.decode(req); if (isLeft(r)) { console.log(PathReporter.report(r)); } else { console.log("validate success"); }
实际校验显示成功,但期望因存在未声明的description属性而触发错误,请问如何基于io-ts实现这种严格校验?
解决方案
方法1:直接使用t.strict替代t.type
io-ts中的t.type会忽略对象中多余的属性,而t.strict会开启严格模式,不允许存在任何未声明的属性。只需修改类型定义:
const Request = t.strict({ id: t.string, name: t.string });
此时重新执行校验,多余的description属性会触发校验失败,PathReporter会输出对应的错误信息。
方法2:通过t.refinement添加额外校验逻辑
如果需要保留t.type的原有特性,可使用t.refinement给类型添加严格属性检查:
import * as t from 'io-ts'; // 先定义基础类型 const RequestBase = t.type({ id: t.string, name: t.string }); // 封装严格校验的类型 const Request = t.refinement(RequestBase, (obj) => { const allowedKeys = new Set(Object.keys(RequestBase.props)); // 检查输入对象的所有属性都在允许列表中 return Object.keys(obj).every(key => allowedKeys.has(key)); }, 'StrictRequest'); // 执行校验 const r = Request.decode(req); if (isLeft(r)) { console.log(PathReporter.report(r)); } else { console.log("validate success"); }
当存在未声明属性时,refinement会返回false,校验失败并输出错误提示。
方法3:自定义严格解码函数
通过fp-ts的管道操作,先完成基础校验,再对比输入对象与校验后对象的属性数量,判断是否存在多余属性:
import * as t from 'io-ts'; import { pipe } from 'fp-ts/function'; import { map } from 'fp-ts/Either'; // 自定义严格解码函数 const strictDecode = <T>(type: t.Type<T>) => (input: unknown) => pipe( type.decode(input), map(validated => { // 只保留类型中声明的属性 const allowedKeys = Object.keys(type.props); return Object.fromEntries( allowedKeys.map(key => [key, (validated as any)[key]]) ) as T; }) ); // 使用示例 const Request = t.type({ id: t.string, name: t.string }); const r = strictDecode(Request)(req); if (isLeft(r)) { console.log(PathReporter.report(r)); } else { const filteredKeys = Object.keys(r.right); const inputKeys = Object.keys(req); // 对比属性数量,不一致则说明有多余属性 if (filteredKeys.length !== inputKeys.length) { const extraProps = inputKeys.filter(k => !filteredKeys.includes(k)).join(', '); console.log(`存在未声明的属性:${extraProps}`); } else { console.log("validate success"); } }
内容的提问来源于stack exchange,提问作者Colin Han
相关产品推荐
相关产品推荐

