在 Javascript 表达式中使用 throw

问题描述 投票:0回答:9

这就是我想做的:

var setting = process.env.SETTING || throw new Error("please set the SETTING environmental variable");
                                     ^^^^^

但是解释器抱怨“语法错误:意外的令牌抛出”。

有没有办法在我们比较值是否为假的同一行中抛出异常?

javascript node.js throw
9个回答
38
投票

您可以利用 javascript 的函数性质。可以使用

function() {}()
立即调用函数(表达式)。这称为立即调用函数表达式 (IFFE)。

x || y
称为短路评估

var setting = process.env.SETTING || function() {
  throw "please set the SETTING environmental variable"; }();

// es201x
const setting = process.env.SETTING || ( () => {
  throw `SETTING environmental variable not set`; } )();

或更通用的创建一个函数来抛出错误并使用它:

function throwErr(mssg){
    throw new Error(mssg);
}

var setting = process.env.SETTING || 
               throwErr("please set the SETTING environmental variable");

我使用的片段:

const throwIf = (
  assertion = false,              // default false
  message = `An error occurred`,  // default Error message string
  ErrorType = Error               // default errorType generic Error
) => {
    // throw if assertion is true, otherwise do nothing
    if (assertion) {
      throw new ErrorType(message);
    }
};
const windowSettingSet = window.SOMESETTING;
// !windowSettingSet is true, so will throw
throwIf(!windowSettingSet, `window.SOMESETTING not defined`, TypeError);


23
投票

throw
是一个语句,而不是一个表达式,因此您不能将其用作另一个表达式的一部分。你必须把它分开:

var setting = process.env.SETTING;
if (!setting) throw new Error("please set the SETTING environmental variable");

9
投票

有一个提案草案将 throw 表达式(类似于 C# 7 的 throw 表达式)引入 JavaScript/ECMAScript:

TC39 提案:抛出表达式


3
投票

用牙套把它包起来

{throw ...}

或者用函数包裹它(实际上是把它包裹在大括号内)

()=>{throw ..}
//or:
function(){throw..}

1
投票

throw
没有返回值。所以你不能那样使用它。但是,您可以将 throw 包装在函数中。那就行了。但要找到异常的根源会更加困难。


1
投票

我看到你使用nodejs。

我认为验证输入参数的最好方法是断言。 NodeJS 内置了简单的断言模块:http://nodejs.org/api/assert.html

并使用它,例如,像这样:

var assert = require('assert');

// ...

function myFunction (param) {
    assert(param, 'please pass param');
    // ...
}

对于测试环境,你可以这样做:

require('assert')(process.env.setting, 'please set the SETTING environmental variable');

或者:

;(function (a) {
    a(process.env.setting, 'please set the SETTING environmental variable');
    a(process.env.port, 'please set the PORT environmental variable');
}(require('assert')));

1
投票
const getenv = require('getenv');
const setting = getenv('SETTING');

如果 SETTING 不存在,您将得到:

… getenv.js:14
throw new Error('GetEnv.Nonexistent: ' + varName + ' does not exist ' +
^ Error: GetEnv.Nonexistent: SETTING does not exist and no fallback value provided.

顺便说一句,我的经验告诉我,环境变量的默认值是邪恶的。


1
投票

不是问题的直接答案,但如果您使用 TypeScript,我发现 runtypes 是手动验证和抛出的绝佳替代方案。虽然 OP 中的方法在输入类型为

output | null | undefined
或类似类型时有效,但运行类型在输入类型为
any
时也有效,例如在防御性解码具有已知结构的 JSON 时。

你会像这样使用它:

import { String } from 'runtypes';
const setting = String.check(process.env.SETTING)

如果

process.env.SETTING
undefined
,则会抛出异常。添加
.withConstraint()
以添加其他条件。该库实际上非常强大,不仅可以验证简单类型,还可以以类型安全的方式验证记录(接口)、联合等。

一个缺点是您无法自定义错误消息(“约束检查失败”),这在许多快速而肮脏的情况下是可以的,因为发生错误的行会告诉您问题是什么。

io-ts 是另一个类似的库,尽管它似乎有更复杂的方法并且目前正在不断变化。


0
投票

虽然不可能直接使用

throw
作为表达式,但它可以像 Koooilnc 那样用在立即调用的匿名闭包中,或者像 casablanca 那样分成自己的语句,或者用 Node 的
assert 替换
正如 Alex Yarochevich 建议的那样。

但是,今天最常见和最惯用的方法可能是使用

tiny-invariant
或类似的函数。

invariant(process.env.SETTING, "SETTING environment variable is required");
const setting = process.env.SETTING;

const setting = process.env.SETTING;
invariant(setting, "SETTING environment variable is required");

它比立即调用的匿名闭包更简单,比单独的 if-throw 语句更清晰、更短(因为条件没有反转),并且与 Node 的

assert
不同,适当缩小了 TypeScript 中的类型范围,并且可以在浏览器中使用。

它也比我之前的建议使用运行时类型库要轻量得多。

© www.soinside.com 2019 - 2024. All rights reserved.