Fix Error: Cannot Redeclare Block-Scoped Variable in TypeScript
Tags: webdev, typescript, debug, beginners
Published: 2022-12-15 06:31:51

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](#the-concept-of-scope)
- [Understanding the Error](#understanding-the-error)
- [Fixing the Error](#fixing-the-error)
  * [Scenario 1: Same variable in same block](#scenario-1--same-variable-in-same-block)
  * [Scenario 2: Same variable in same project](#scenario-2--same-variable-in-same-project)
- [Conclusion](#conclusion)

## 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:

```javascript
function myFunction() {
  let foo = 1;
  let foo = 2;
}
```

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

```javascript
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:

```javascript
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:

```javascript
let foo = 1;
```

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

```javascript
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](https://www.typescriptlang.org/docs/handbook/modules.html#handbook-content),

> 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:

```javascript
let foo  = 1;
export {}; // add this line
```

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

```javascript
{
  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:

```json
{
  "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](https://stackoverflow.com/a/50913569/19012032) and [this thread](https://github.com/microsoft/TypeScript/issues/9466#issuecomment-230089243)), but no error is thrown even if I _KEEP_ the DOM typings:

 ```json
{
  "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,

```json
{
  "compilerOptions": {
    "lib": ["ES6"]
  }
}
```

did the trick, please comment below. Thank you.