π Disallow declarations before conditional early exits when they are only used after the exit.
πΌ This rule is enabled in the following configs: β
recommended, βοΈ unopinionated.
π§ This rule is automatically fixable by the --fix CLI option.
Declare variables as close as possible to where they are used. If a variable is declared before a guard clause but only used after it, the declaration can be moved below the guard. This avoids unnecessary initialization on the early-exit path and keeps the variable scope tighter.
This rule reports declarations before return, throw, break, and continue guard clauses.
// β
function foo(bar) {
const result = 1;
if (!bar) {
return;
}
console.log(result);
}// β
function foo(bar) {
if (!bar) {
return;
}
const result = 1;
console.log(result);
}// β
function foo(bar) {
const result = 1;
if (!bar) {
throw new Error();
}
console.log(result);
}// β
function foo(bar) {
if (!bar) {
throw new Error();
}
const result = 1;
console.log(result);
}// β
function foo(bar) {
const result = getResult();
if (!bar) {
return;
}
console.log(result);
}The last example is reported without an autofix because moving a function call can change observable behavior.
This rule intentionally uses a simple statement-list scan instead of full data-flow analysis. It only checks declarations and guard clauses that are direct children of the same block or top-level program. Switch cases are only checked when the case body is wrapped in a block. Non-adjacent declarations with nontrivial initializers are ignored because moving them across intervening statements can change values or timing. Declarations are also ignored when the initializer and the guard share a variable that either side mutates, since reordering them would change behavior (for example, const x = array.pop() before if (array.length > 0)).
Declarations whose initializer contains await or yield are ignored: moving them below the guard would evaluate the guard condition before the suspension instead of after it, which can change observable timing.
Declarations initialized by a React hook call (for example, const value = useMemo(β¦)) are ignored, because hooks must run unconditionally and moving one below an early exit would violate the Rules of Hooks.