throw
expressions
This proposal defines new syntax to throw exceptions from within an expression context.
Stage: 2
Champion: Ron Buckton (@rbuckton)
For more information see the TC39 proposal process.
A throw
expression allows you to throw exceptions in expression contexts. For example:
function save(filename = throw new TypeError("Argument required")) { }
lint(ast, { with: () => throw new Error("avoid using 'with' statements.") });
function getEncoder(encoding) { const encoder = encoding === "utf8" ? new UTF8Encoder() : encoding === "utf16le" ? new UTF16Encoder(false) : encoding === "utf16be" ? new UTF16Encoder(true) : throw new Error("Unsupported encoding"); }
class Product { get id() { return this._id; } set id(value) { this._id = value || throw new Error("Invalid value"); } }
A throw
expression does not replace a throw
statement due to the difference in the precedence of their values. To maintain the precedence of the throw
statement, we must add a lookahead restriction to ExpressionStatement
to avoid ambiguity.
Due to the difference in precedence between a throw
expression and a ThrowStatement, certain operators to the right of the expression would parse differently between the two which could cause ambiguity and confusion:
throw a ? b : c; // evaluates 'a' and throws either 'b' or 'c' (throw a ? b : c); // without restriction would throw 'a', so `?` is forbidden throw a, b; // evaluates 'a', throws 'b' (throw a, b); // would throw 'a', not 'b', so `,` is forbidden throw a && b; // throws 'a' if 'a' is falsy, otherwise throws 'b' (throw a && b); // would always throw 'a', so `&&` is forbidden throw a || b; // throws 'a' if 'a' is truthy, otherwise throws 'b' (throw a || b); // would always throw 'a', so `||` is forbidden // ... etc.
As a result, all binary operators and the ?
operator are forbidden to the right of a throw
expression. To use these operators inside of a throw
expression, the expression must be surrounded with parentheses:
(throw (a, b)); // evaluates 'a', throws 'b' (throw (a ? b : c)); // evaluates 'a' and throws either 'b' or 'c'
However, we do not forbid :
so that a throw
expression can still be easily used in a ternary:
const x = a ? throw b : c; // if 'a' then throw 'b', else evaluate 'c'
++ThrowExpressionInvalidPunctuator : one of `,` `<` `>` `<=` `>=` `==` `!=` `===` `!==` `+` `-` `*` `/` `%` `**` `<<` `>>` `>>>` `&` `|` `^` `&&` `||` `??` `=` `+=` `-=` `*=` `%=` `**=` `<<=` `>>=` `>>>=` `&=` `|=` `^=` `&&=` `||=` `??=` `?` UnaryExpression[Yield, Await] : ++ `throw` UnaryExpression[?Yield, ?Await] [lookahead ∉ ThrowExpressionInvalidPunctuator] ExpressionStatement[Yield, Await] : -- [lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`}] Expression[+In, ?Yield, ?Await] `;` ++ [lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`, `throw`}] Expression[+In, ?Yield, ?Await] `;`
A throw
expression can be approximated in ECMAScript using something like the following definition:
const __throw = err => { throw err; }; // via helper... function getEncoder1(encoding) { const encoder = encoding === "utf8" ? new UTF8Encoder() : encoding === "utf16le" ? new UTF16Encoder(false) : encoding === "utf16be" ? new UTF16Encoder(true) : __throw(new Error("Unsupported encoding")); } // via arrow... function getEncoder2(encoding) { const encoder = encoding === "utf8" ? new UTF8Encoder() : encoding === "utf16le" ? new UTF16Encoder(false) : encoding === "utf16be" ? new UTF16Encoder(true) : (() => { throw new Error("Unsupported encoding"); })(); }
However, this has several downsides compared to a native implementation:
__throw
helper will appear in err.stack
in a host environment.
Error.captureStackTrace
throw
is not local to the function.The following is a high-level list of tasks to progress through each stage of the TC39 proposal process:
Stage 1 Entrance CriteriaRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4