【问题标题】:How to efficiently validate all args in Javascript functions?如何有效地验证 Javascript 函数中的所有参数?
【发布时间】:2021-12-20 19:23:08
【问题描述】:

我使用 Javascript (Typescript),更具体地说是使用 React。所以这个问题是用 Javascript 编写的,但它更像是一个一般问题。

我正在尝试重构一些代码并提取静态方法。提取方法后,我发现自己正在检查收到的所有参数是否有效。这变得难以阅读,有时,函数的真正目的只有几行。

这是我最终如何编写方法/函数的示例

const isGreaterThan = (value1, value2) => {
  if(typeof value1 !== 'number'){
    console.error("Invalid argument. value1 must be a number");
    return 0;
  }
  if(typeof value2 !== 'number'){
    console.error("Invalid argument. value2 must be a number");
    return 0;
  }
  return value1 > value2
}

现在想象一下,如果这个方法收到一个Array

const isGreaterThanAll = (values, value1) => {
  if(!values instanceof Array){
    console.error("Invalid argument. values must be an Array");
    return 0;
  }
  if(!values.every(value => typeof value === 'number')){
    console.error("Invalid argument. elements of values must be numbers");
    return 0;
  }
  if(typeof value1 !== 'number'){
    console.error("Invalid argument. value2 should be type of number");
    return 0;
  }
  return values.every(value => value1 > value);
}

现在想象传递ObjectArrayObjects。根据论点的复杂性,这变得更难理解。

我的一些问题是:

  • 在这种情况下重构代码的最佳实践是什么?
  • 如何重构这种代码以使其更具可读性?
  • 我应该建立一个方法来检查参数吗?

【问题讨论】:

  • 你在哪里使用这些功能?只是在您自己的代码库中,还是它们暴露在外部?如果它是您的代码库并且您说您正在使用打字稿,只需为参数分配一个类型,例如const isGreaterThan = (value1: number, value2: number)
  • @szaman 有时我只在内部使用它们,我可以信任 Typescript,但在某些情况下,我还需要在运行时检查错误,例如当我将它们与 API 响应一起使用时。在这种情况下,编译时间对我不起作用,因为如果我假设一个类型并且它发生了变化,它将在生产中默默地失败:'(
  • @Lukas 这看起来像 TDD 但反过来。对于这种情况,您首先编写测试,然后在测试中检查类型是否正确并对某些最终结果进行断言。在构建并投入生产之前,您正在运行测试套件并检查您的函数是否给出异常结果。我认为更好的方法是像 szaman 所说的那样添加类型提示,并为这些功能添加测试,如果你可以放置你的过滤器。另一个建议是创建某种 json 模式,您可以通过它来验证您的参数。
  • @Lucas 使用打字稿并信任您声明的类型。从您的业务逻辑和辅助函数中删除类型验证。如果您不信任 API 响应,请检查 that 以了解您收到它的类型;有效时将其传递给您的函数。不要在 isGreaterThanisGreaterThanAll 这样的函数中进行验证,它在那里没有位置。
  • @Lucas 如果你使用的是 JEST,那么首先看看这个thread。而不是逐个测试,我宁愿将describe with map 与之前的线程答案结合使用。

标签: javascript typescript validation types typeof


【解决方案1】:

一种方法是创建这样的递归函数。

const isNumberOrArrayOfNumbers = (x) => {
  if (typeof x === 'number') {
    return true;
  }
  if ( Array.isArray(x) ) {
    return x.every(n => isNumberOrArrayOfNumbers(n));
  }
  return false;
};

const isGreaterThanAll = (values, value1) => {

  let valid = [values, value1].every(a => isNumberOrArrayOfNumbers(a));
  
  if (!valid) {
    console.error('Invalid');
    return Number.NaN;
  }


  return values.every(value => value1 > value);
};

console.log( isGreaterThanAll([1,2,3,5,6,7],12) );
console.log( isGreaterThanAll([1,2,3,5,6,7],4) );
console.log( isGreaterThanAll([1,2,3,"r",5,6,7],12) );

如果您愿意更改函数的签名,您还可以通过使其成为可变参数并使用 rest operators 进行重构

可能看起来像这样:

const isGreaterThanAll = (n, ...m) => {
    let valid = [n, ...m].every(x => typeof x === 'number');
    ...
};

【讨论】:

    猜你喜欢
    • 2020-03-26
    • 2013-12-19
    • 2022-08-23
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多