如何高效校验JavaScript函数所有入参?相关最佳实践有哪些?
这类场景的重构最佳实践
核心原则是静态校验和运行时校验分离,校验逻辑和业务逻辑解耦:
- 优先依赖TypeScript类型系统做编译期校验,内部调用的函数完全可以靠TS的类型检查覆盖绝大多数参数错误场景,不需要额外写运行时代码校验。
- 只有当入参来自接口返回、用户输入、本地存储这类不可控的外部数据源时,才需要补充运行时校验。
- 禁止把大段校验代码和业务核心逻辑堆在同一个函数内。
重构提升可读性的具体方案
你可以按以下步骤优化现有代码:
第一步:先补全TS类型定义,砍掉不必要的运行时校验
比如你给出的示例函数,仅靠类型定义就能在开发阶段拦截所有传参类型错误,不需要额外写判断:
// 内部调用时传非number类型TS会直接报错,不需要运行时校验 const isGreaterThan = (value1: number, value2: number): boolean => { return value1 > value2 }
补充:你原有代码里的!values instanceof Array存在运算符优先级问题,实际执行的是(!values) instanceof Array永远返回false,建议统一用Array.isArray做数组判断更稳妥。
第二步:必须保留运行时校验的场景,用高阶函数抽离校验逻辑
你可以封装通用的参数校验高阶函数,把校验规则和业务逻辑完全拆分:
// 通用校验规则类型定义 type ValidateRule = (val: any) => { pass: boolean, errMsg?: string } // 校验高阶函数,入参为校验规则列表、校验失败返回值 const withValidate = (rules: ValidateRule[], failReturn: any = 0) => { return (fn: Function) => { return (...args: any[]) => { // 按参数顺序依次校验 for (let i = 0; i < rules.length; i++) { const checkRes = rules[i](args[i]) if (!checkRes.pass) { console.error(checkRes.errMsg) return failReturn } } return fn(...args) } } }
使用时只需要给业务函数包裹一层校验逻辑即可,业务函数里完全不需要写校验相关代码:
// 通用校验规则可全局复用,不需要每个函数重复写 const isNumber: ValidateRule = (val) => ({ pass: typeof val === 'number', errMsg: 'Invalid argument. value must be a number' }) const isNumberArray: ValidateRule = (val) => { if (!Array.isArray(val)) return { pass: false, errMsg: 'Invalid argument. values must be an Array' } if (!val.every(item => typeof item === 'number')) return { pass: false, errMsg: 'Invalid argument. elements of values must be numbers' } return { pass: true } } // 业务逻辑完全干净,核心逻辑一目了然 const isGreaterThan = withValidate([isNumber, isNumber])( (value1: number, value2: number) => value1 > value2 ) const isGreaterThanAll = withValidate([isNumberArray, isNumber])( (values: number[], value1: number) => values.every(v => value1 > v) )
第三步:复杂入参场景可封装组合式校验规则
如果后续需要校验对象、对象数组这类复杂结构,你可以提前把字段判存、字段类型校验、嵌套结构校验等通用逻辑封装成独立的规则生成函数,需要的时候直接组合规则即可,不用每次重复写判断逻辑。
是否应该单独封装通用的入参校验方法?
完全应该,投入成本很低但收益非常高:
- 校验逻辑统一维护,后续要改错误提示格式、校验失败返回值、新增错误上报逻辑只需要改一处封装代码,不需要逐个修改业务函数。
- 避免大量重复代码,同类型的校验规则只需要写一次,所有业务函数都可以复用。
- 业务函数可读性大幅提升,核心逻辑没有冗余代码干扰,后续迭代维护成本很低。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

