do expressions S1
- Stage: Stage 1
- Status: Active
- ECMAScript edition: —
- Synchronized: Aug 28, 2026
- 中文译文 · Source repository
The do expressions proposal introduces expression-oriented programming to ECMAScript by allowing block statements to be used as expressions, returning the completion value of the last statement. It aims to simplify code that currently uses nested ternaries or statement sequences, and is particularly useful in templating contexts like JSX.
The README below comes from the upstream repository and may contain outdated stage or status metadata. Use the proposal details above as the current source of truth.
ECMAScript proposal: do expressions
This proposal has preliminary spec text.
Status
This proposal is in stage 1 of the TC39 process.
Motivation
- expression-oriented programming one of the great advances of FP
- expressions plug together like legos, making more malleable programming experience in-the-small
Examples
Write in an expression-oriented style, scoping variables as locally as possible:
Use conditional statements as expressions, instead of awkward nested ternaries:
Especially nice for templating languages like JSX:
Limitations
Because of the potential for confusion, you can't end a do-expression with a declaration, an if without an else, or a loop (even when nested in other statements). For example, the following are all Early Errors:
More formally, the completion value of the StatementList can't rely on the completion value of a loop or declaration. See EndsInIterationOrDeclaration in the proposed specification for details.
The restriction on declarations is particularly unfortunate. It arises from the fact that declarations have ~empty~ as their completion value, meaning do { 'before'; let x = 'after'; } would evaluate to before. I'd like to pursue changing the completion value for declarations in general, which would affect existing code relying on eval.
Edge cases
var declarations
var declarations are allowed (except as the final statement), with the binding hoisting to the containing function's scope. Exception: var declarations are an Early Error when the do occurs in a parameter expression.
Empty do
do {} is allowed and is equivalent to void 0.
await/yield
The ability to use await and yield is inherited from the context of the enclosing function, as it is in any other expression.
throw
Works fine. Does what you expect.
break/continue/return
These are allowed when in an appropriate context: return is allowed when the do is within a function, break is allowed when within a loop or a switch case, etc. This allows you to write code like this:
Exceptions
Because of the potential for confusion, unlabeled break and continue are not allowed within the head of a loop, whether or not the loop is within another loop.
return is allowed even within function parameter lists, as in function f(x = do { return null; }) {}. It is not allowed in computed property names in class bodies.
Conflict with do-while
do expressions are prohibited in contexts in which statements are legal. In such contexts you can just use a normal block or enclose the do expression in parentheses.
B.3.3 function hoisting
Sloppy-mode function hoisting is not allowed to pass through a do-expression.