All posts
typescriptcompiler

Fixing "Cannot redeclare block-scoped variable" in TypeScript

Why TypeScript blocks redeclaring let/const variables in the same scope, and how to fix each common cause.

SR

Suhail Roushan

August 6, 2026

·
5 min read
·
0 views

Cannot redeclare block-scoped variable 'X' is TypeScript enforcing a rule that's actually part of core JavaScript semantics since ES6 — let and const declarations are block-scoped and cannot be declared twice in the same scope, unlike the older, more permissive var, which TypeScript surfaces as a compile-time error rather than letting it become a confusing runtime SyntaxError.

This error means you've declared the same variable name twice with let or const within a scope where JavaScript's block-scoping rules don't allow it — commonly from accidental duplication, a loop variable colliding with an outer declaration, or a merge/refactor that introduced a naming collision.

Why This Error Happens

Unlike var, which is function-scoped and permits (with warnings in strict mode) redeclaration, let and const are strictly block-scoped and JavaScript itself throws a SyntaxError for a genuine redeclaration in the same block — TypeScript catches this at compile time instead, which is strictly better since it surfaces the problem before your code ever runs.

Reproducing the Error

Straightforward accidental duplication:

function processItems(items: Item[]) {
  let total = 0;
  // ... later in the same function
  let total = 0; // Error: Cannot redeclare block-scoped variable 'total'.
}

A loop variable colliding with an outer-scope declaration of the same name:

function summarize(orders: Order[]) {
  const order = getCurrentOrder();
  for (const order of orders) {
    // Error: Cannot redeclare block-scoped variable 'order'.
    // (shadowing is allowed in nested blocks, but this specific structure
    // depends on exactly where each declaration sits — check scope carefully)
    process(order);
  }
}

Core Concepts Behind This Error

True block-scoped shadowing (a let/const inside a nested block reusing a name from an outer scope) is legal JavaScript and doesn't produce this error — the error specifically means two declarations exist in the exact same scope, not merely similarly-named variables at different nesting levels; understanding this distinction is key to correctly diagnosing where the actual conflict lives.

Switch statement case blocks share a single scope unless each case has its own braces, a commonly surprising source of this error — declaring the same let/const name in two different case blocks of the same switch without wrapping each case in {} produces this error, since both cases are technically in the same enclosing block scope.

Function parameter names colliding with a subsequent let/const declaration inside the function body is another common, easy-to-miss cause — the parameter itself counts as a declaration in the function's scope.

This error is distinct from simple reassignment, which is entirely valid for let (just not const) — the error only fires for actual re-declaration (a second let/const/var/class/function with the same name), not for total = total + 1, which is ordinary reassignment.

Fixing "Cannot Redeclare Block-Scoped Variable"

Fix 1: Rename one of the conflicting declarations to a distinct, clear name:

function processItems(items: Item[]) {
  let total = 0;
  // ...
  let itemCount = 0; // renamed
}

Fix 2: For switch statement case-block collisions, wrap each case in its own braces to create distinct block scopes:

switch (action.type) {
  case "add": {
    const result = a + b;
    return result;
  }
  case "subtract": {
    const result = a - b; // no longer conflicts — separate block scope
    return result;
  }
}

Fix 3: For parameter name collisions, rename either the parameter or the conflicting local declaration:

function processOrder(order: Order) {
  const processedOrder = transform(order); // renamed the local variable instead
  return processedOrder;
}

Fix 4: If the second declaration was meant to just reassign an existing variable, remove the redundant let/const keyword:

let total = 0;
// ...
total = calculateTotal(items); // reassignment, not redeclaration — no keyword needed

Why Do Switch Statement Cases Share Scope by Default?

Because a switch statement's body is a single block unless you explicitly add braces around individual case clauses — all case labels within it are part of that one enclosing block scope by default, which is why a let/const declared in one case is visible (and can conflict) with declarations in other cases of the same switch, even though execution only ever enters one case at a time. Wrapping each case in {} creates genuinely separate block scopes, which is why that's the standard fix.

Preventing This Error in Production

Prefer distinct, descriptive variable names throughout a function rather than reusing generic names like result or total across multiple logical sections, reducing the chance of accidental collision as functions grow. Wrap switch statement case bodies in braces as a default habit whenever they contain variable declarations, avoiding this class of error before it happens rather than discovering it through a compile failure.

If you hit this error, check whether the two declarations are genuinely in the same scope (not just similarly indented) — switch case blocks without individual braces are a frequent, easy-to-miss cause worth checking first.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch