JavaScript参数类型检查

时间:2019-06-07 04:32:25

标签: javascript reactjs mobx

我一直在用尽我的Google-fu来寻找有关如何在ES6模块方法中最佳断言参数的示例,或处理可能传递的数据类型的不确定性的示例。即介于字符串和数字类型之间。我刚刚花了几个小时来解决关于计算属性和MobX的怪异行为问题,在这里我有一些测试代码可以初始化默认值的发送,并且效果很好。计算值取一个初始值,从相关数据(贷方和借方)中求出两个总数,然后加上借方并扣除贷方以返回调整后的值。因此,返回的initialValue(1000)+ totalDebits(0)-totalCredits(0)返回1000。简单。但是,当我添加一个对话框以将初始值输入2000到列表中的新项输入时,我的计算值又回到了20000!奇怪的是,我将这些对象保留在本地存储中,当我从存储的值刷新时,计算出的总数仍为20000,而其他现有值具有与初始值匹配的正确计算值。

我终于找到了原因,并在持久状态下进行了验证,以确保输入页面中的initialBalance被存储为字符串文字“ 2000”。 “ 2000” + 0-0为字符串添加了0,而负号被忽略了。

我的问题是,普通JS或合适的ES6库有哪些选项可用于处理可能会进入功能(例如MobX动作)的类型?加上一般处理JS参数时的最佳做法建议。

例如: 在我的组件中,我有一个onChange事件

onInitialBalanceChange(e){
    const value = e.target.value;
    const account = this.state.account;
    let validationError = null;
    let isBalanceValid = true;
    if(!this.validateInitialBalance(value)){
        validationError = 'The initial balance must be a positive number.'
        isBalanceValid = false;
    } 
    account.updateInitialBalance(value);
    this.setState({validationError: validationError, isBalanceValid: isBalanceValid, isComplete: isBalanceValid && this.state.isNameValid});
}

updateInitialBalance已注册为MobX动作:

updateInitialBalance(initialBalance){
    if (!!initialBalance) this.initialBalance = initialBalance;
    return this;
}

这是我的问题/关注的地方,而且令我惊讶的是,我对解决JS参数类型和类型转换(除了进行单独检查的功能的解释以外)没有真正看到太多东西。我的组件对余额进行验证检查,并且可以将余额作为数字返回,但是仍然使update方法可能仍在其他地方用数字字符串调用。 我有一个断言,该参数不是null / empty,但是除了有效的if()条件数量以外,断言/转换其类型的最佳实践是什么? initialBalance可以是字符串“ 2000”或数字2000,并且还应防止使用无效数据,例如“ fred”?因此,我提出了一个问题,要求在鸭子式世界中进行可靠的类型检查。

从我看来,这似乎可行,但是根据文档,感觉有点“错”:

if (!!initialBalance) this.initialBalance = parseInt(initialBalance);

parseInt接受“字符串”,但是,如果initialBalance已经是一个数字(而不是数字字符串),这似乎也可以工作。

我知道这是一个自以为是的问题,但是我真的在寻找选择,因为我内在的C#开发人员的尖叫声震耳欲聋。 :)

1 个答案:

答案 0 :(得分:1)

听起来这里有三个问题。这些只是我认为应该为每个人提供帮助的一些意见。

如何最好地访问本地存储?

要从本地存储中存储和检索值,您可能需要编写某种包装模块,该包装模块应执行以下操作:

class LocalStorageWrapper {

    setInitialBalanace(balance){
        if(Object.prototype.toString.call(balance) !== '[object Number]') return false;
        // any other validation. > 0? < 9999999? etc
        // set the value
    }

    getInitialBalance(){
        const val = // get the value from local storage
        if(!isNaN(parseFloat(val)) && isFinite(val)) return parseInt(val);
        if(Object.prototype.toString.call(val) === '[object Number]') return val;
        // return some default value. The value is either unset or corrupted
    }
}

注意:

  • 使用它来访问整个代码库中的本地存储,以免您在各地重复进行这些检查。还要对其中的废话进行单元测试。
  • Object.prototype.toString.call(balance) !== '[object Number]'是IMO检验有意义数字的最佳方法。有关测试用例,请参见here
  • !isNaN(parseFloat(val)) && isFinite(val)best way,用于测试可以可靠地解析为数字的“数字”值。

是否有方便的模式来检查用户错误

对于一般验证,我认为通常会比较安全的方法是抛出一个非常具体的错误并最终将其捕获。例如:

onInitialBalanceChange(e){

    try {
        if(!this.validateInitialBalance(value)){
            throw new Error('initial_balance_negative')
        }
        // other error checks here...
        account.updateInitialBalance(value); // do whatever you want
        this.setState({validationError: null, isBalanceValid: isBalanceValid, isComplete: isBalanceValid && this.state.isNameValid});
    } catch(e) {
        // ideally match against some expected
        if(constantStrings.hasOwnProperty(e.message)){
            this.setState({validationError: constantStrings[e.message]}); // an 'expected' user error
        }else{
            this.setState({validationError: 'Unknown error'}); // a 'true' error
        }
    }

}

// somewhere else in 'strings.js' or something
const constantStrings = {
    initial_balance_negative: 'The initial balance must be a positive number.'
};

鸭子式JS很难

我知道:(。但是我强烈建议您使用Typescript。学习曲线的确不是太陡峭,如果您可以选择使用它,请使用它。它会为您提前捕获很多错误(包括本地存储是一个字符串值存储错误),并保存所有麻烦的单元测试这些东西。