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;
}
You can fix it by either renaming the second foo
variable:
function myFunction() {
let foo = 1;
let bar = 2; // renamed to bar
}
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
}
}
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
In main.ts
, we have this code:
let foo = 1;
Then, we compile main.ts
to main.js
and now, main.js
has the following code:
var foo = 1;
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 foo
s 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
Or we can also wrap the variable with {}
to move it into a local scope:
{
let foo = 1;
}
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"]
}
}
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"]
}
}
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"]
}
}
did the trick, please comment below. Thank you.
Top comments (0)