Fix Error: Cannot Redeclare Block-Scoped Variable in TypeScript

jessewei

Jesse Wei

Posted on December 15, 2022

Fix Error: Cannot Redeclare Block-Scoped Variable in TypeScript

If you're using Typescript, it's likely you've run into this error, "Cannot redeclare block-scoped variable" a couple of times.

Although the issue is discussed widely online across multiple platforms, I could not find a comprehensive source explaing the why and the fix in depth.

So I wrote this article to help you understand the problem in context, look at different scenarios where you can run into the error and how to fix it in each scenario.

Table of Contents

The Concept of Scope

To understand the error and come up with a fix for it, we need to understand the concept of scope first.

Scope refers to the visibility and accessibility of variables and functions in different parts of your code. There are two main types of scope in JavaScript (Typescript): global scope and local scope.

Global scope refers to the scope where variables and functions can be accessed throughout your entire file or project. Variables and functions that are declared at the top level of your code, outside of any functions or blocks, are considered to be in global scope.

Local scope, on the other hand, refers to the visibility and accessibility of variables and functions within a specific block of code, such as within a function or a block of code delimited by curly braces ({}). Variables and functions that are declared within a block of code are considered to be in local scope and are only accessible within that block of code.

Understanding the Error

Now that we learned what a scope is, we can better understand the error "Cannot redeclare block-scoped variable 'foo'". As you may have realized, it basically says we're trying to declare a variable named foo in the same scope where a variable named foo already exists.

Fixing the Error

There can be a couple of different scenarios where you might run into this error and so we need to take a look at how to fix it in those scenarios.

Scenario 1: Same variable in same block

For example, this code throws the error mentioned because the variable foo is declared twice in the same function block:

function myFunction() {
  let foo = 1;
  let foo = 2;
}
Enter fullscreen mode Exit fullscreen mode

You can fix it by either renaming the second foo variable:

function myFunction() {
  let foo = 1;
  let bar = 2; // renamed to bar
}

Enter fullscreen mode Exit fullscreen mode

Or by moving the declaration of the second foo variable to a different block of code:

function myFunction() {
  let foo = 1;

  if (foo === 1) {
    let foo = 2; // a different scope
  }
}
Enter fullscreen mode Exit fullscreen mode

Scenario 2: Same variable in same project

Say we have a simple project with the following hierarchy.

.
├── main.js
├── main.ts
├── node_modules
├── package-lock.json
└── package.json
Enter fullscreen mode Exit fullscreen mode

In main.ts, we have this code:

let foo = 1;
Enter fullscreen mode Exit fullscreen mode

Then, we compile main.ts to main.js and now, main.js has the following code:

var foo = 1;
Enter fullscreen mode Exit fullscreen mode

Now back to the main.ts file and we get the error saying, "Cannot redeclare block-scoped variable 'foo'", even though we only declared foo once in our file.

This is because variables declared in a file, which does not have a top-level import or export, are available in the entire project. According to Typescript Docs,

Any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope.

Since we have another foo in main.js, Typescript complained with the error.

To fix this, we have a couple of options. First, we can just rename one of the foos to something else as we did in scenario 1, but most likely this is not desirable as we don't want to rename every variable after compilation.

Then, we can just add an export to main.ts to make it a module:

let foo  = 1;
export {}; // add this line
Enter fullscreen mode Exit fullscreen mode

Or we can also wrap the variable with {} to move it into a local scope:

{
  let foo  = 1;
}
Enter fullscreen mode Exit fullscreen mode

Another option to get rid of the error is, if you have tsconfig.json in your project root, adding the following setting:

{
  "compilerOptions": {
    "lib": ["ES6"]
  }
}
Enter fullscreen mode Exit fullscreen mode

I googled multiple sources to find out why this works but unfortunately could not get a persuasive answer. Some argue it's about opting out Typescript's DOM typings (check out this answer and this thread), but no error is thrown even if I KEEP the DOM typings:

{
  "compilerOptions": {
    "lib": ["DOM", "ES6"]
  }
}
Enter fullscreen mode Exit fullscreen mode

If you've got a better answer, feel free to share in the comments below.

Conclusion

In this post, I shared with you a common error in Typescript, the cause of it and how to fix it in different scenarios.

Even though there are quite a few answers and blog posts on this topic, very few of them explored the why in depth and discussed the different cases where you could run into the error.

I hope this article helps and if you have got an idea why this setting,

{
  "compilerOptions": {
    "lib": ["ES6"]
  }
}
Enter fullscreen mode Exit fullscreen mode

did the trick, please comment below. Thank you.

💖 💪 🙅 🚩
jessewei
Jesse Wei

Posted on December 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related