Cannot redeclare block scoped variable

TypescriptRequire

Typescript Problem Overview


I'm building a node app, and inside each file in .js used to doing this to require in various packages.

let co = require("co");

But getting

enter image description here

etc. So using typescript it seems there can only be one such declaration/require across the whole project? I'm confused about this as I thought let was scoped to the current file.

I just had a project that was working but after a refactor am now getting these errors all over the place.

Can someone explain?

Typescript Solutions


Solution 1 - Typescript

Regarding the error itself, let is used to declare local variables that exist in block scopes instead of function scopes. It's also more strict than var, so you can't do stuff like this:

if (condition) {
    let a = 1;
    ...
    let a = 2;
}

Also note that case clauses inside switch blocks don't create their own block scopes, so you can't redeclare the same local variable across multiple cases without using {} to create a block each.


As for the import, you are probably getting this error because TypeScript doesn't recognize your files as actual modules, and seemingly model-level definitions end up being global definitions for it.

Try importing an external module the standard ES6 way, which contains no explicit assignment, and should make TypeScript recognize your files correctly as modules:

import * as co from "./co"

This will still result in a compile error if you have something named co already, as expected. For example, this is going to be an error:

import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;

If you are getting an error "cannot find module co"...

TypeScript is running full type-checking against modules, so if you don't have TS definitions for the module you are trying to import (e.g. because it's a JS module without definition files), you can declare your module in a .d.ts definition file that doesn't contain module-level exports:

declare module "co" {
    declare var co: any;
    export = co;
}

Solution 2 - Typescript

The best explanation I could get is from [Tamas Piro's post][1].

TLDR; TypeScript uses the DOM typings for the global execution environment. In your case there is a 'co' property on the global window object.

To solve this:

  1. Rename the variable, or

  2. Use TypeScript modules, and add an empty export{}:

    export {};
    

    or

  3. Configure your compiler options by not adding DOM typings:

Edit tsconfig.json in the TypeScript project directory.

{
    "compilerOptions": {
        "lib": ["es6"]
      }
}

[1]: https://web.archive.org/web/20180609155906/http://fullstack-developer.academy/cannot-redeclare-block-scoped-variable-name/ "Full Stack Developer Academy - Cannot redeclare block-scoped variable 'name'."

Solution 3 - Typescript

For those coming here in this age, here is a simple solution to this issue. It at least worked for me in the backend. I haven't checked with the frontend code.

Just add:

export {};

at the top of any files with code without an existing export.

Credit to EUGENE MURAVITSKY

Solution 4 - Typescript

I was receiving this similar error when compiling my Node.JS Typescript application:

node_modules/@types/node/index.d.ts:83:15 - error TS2451: Cannot redeclare block-scoped variable 'custom'.

The fix was to remove this:

"files": [
  "./node_modules/@types/node/index.d.ts"
]

and to replace it with this:

"compilerOptions": {
  "types": ["node"]
}

Solution 5 - Typescript

Use IIFE(Immediately Invoked Function Expression), IIFE

(function () {
    all your code is here...
    
 })();

Solution 6 - Typescript

I have also dealt with this issue while working with ts on vscode. The way i fix this is easy, but it might not be the same as your problem.

My editor shows this error when i have the typescript file and the javascript file open at the same time in the recent tabs. I just close it and the error goes away.

Hope this helps someone who may also be scratching their head from this simple bug.

Solution 7 - Typescript

The solution for me was to convert my code from using CommonJS (require, module.exports, etc) to ES Modules (import, export, etc.)

The TypeScript documentation also appears to recommend ES Module syntax: TypeScript Modules

Of course there's a lot more to it than this, but as a start:

  1. Replace instances of require with import, e.g.

    Replace:

    const https = require('https');
    

    With:

    import https from 'https';
    
  2. Replace the default module.exports with export default, e.g.

    Replace:

    module.exports = myVar ...
    

    With:

    export default myVar ...
    
  3. Replace other module.exports with export, e.g.

    Replace:

    module.exports.myVar = 
    

    or:

    module.export = { myVar ... }
    

    With:

    export myVar ...
    

More here: From CommonJS to ES Modules: How to modernize your Node.js app

Solution 8 - Typescript

Here is my fix for my situation. Simple and Fast!!!

enter image description here

This happening when the block-scoped variable have declared somewhere in the source code.

To fix this, remove module.exports = and replace by export default.

Solution 9 - Typescript

In my case the following tsconfig.json solved problem:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "target": "ES2020",
    "moduleResolution": "node"
  }
}

There should be no type: module in package.json.

Solution 10 - Typescript

That´s the editor warning, becaouse, when you have open index.js which is compiled and also index.ts. you will see this.. but when you close index.js it will be ok.

Solution 11 - Typescript

I got the same problem, and my solution looks like this:

// *./module1/module1.ts*
export module Module1 {
    export class Module1{
        greating(){ return 'hey from Module1'}
    }
}


// *./module2/module2.ts*
import {Module1} from './../module1/module1';

export module Module2{
    export class Module2{
        greating(){
            let m1 = new Module1.Module1()
            return 'hey from Module2 + and from loaded Model1: '+ m1.greating();
        }
    }
}

Now we can use it on the server side:

// *./server.ts*
/// <reference path="./typings/node/node.d.ts"/>
import {Module2} from './module2/module2';

export module Server {
    export class Server{
        greating(){
            let m2 = new Module2.Module2();
            return "hello from server & loaded modules: " + m2.greating();
        }
    }
}

exports.Server = Server;

// ./app.js
var Server = require('./server').Server.Server;
var server = new Server();
console.log(server.greating());

And on the client side too:

// *./public/javscripts/index/index.ts*

import {Module2} from './../../../module2/module2';

document.body.onload = function(){
    let m2 = new Module2.Module2();
    alert(m2.greating());
}

// ./views/index.jade
extends layout

block content
  h1= title
  p Welcome to #{title}
  script(src='main.js')
  //
    the main.js-file created by gulp-task 'browserify' below in the gulpfile.js

And, of course, a gulp-file for all of this:

// *./gulpfile.js*
var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    runSequence = require('run-sequence'),
    browserify = require('gulp-browserify'),
    rename = require('gulp-rename');

gulp.task('default', function(callback) {

    gulp.task('ts1', function() {
        return gulp.src(['./module1/module1.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module1'))
    });

    gulp.task('ts2', function() {
        return gulp.src(['./module2/module2.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module2'))
    });
    
    gulp.task('ts3', function() {
        return gulp.src(['./public/javascripts/index/index.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./public/javascripts/index'))
    });

    gulp.task('browserify', function() {
        return gulp.src('./public/javascripts/index/index.js', { read: false })
            .pipe(browserify({
                insertGlobals: true
            }))
            .pipe(rename('main.js'))
            .pipe(gulp.dest('./public/javascripts/'))
    });

    runSequence('ts1', 'ts2', 'ts3', 'browserify', callback);
})

Updated. Of course, it's not neccessary to compile typescript files separatly. runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback) works perfect.

Solution 12 - Typescript

In my case (using IntelliJ) File - Invalidate Caches / Restart... did the trick.

Solution 13 - Typescript

I got the similar error when I was importing express incorrectly. All I had to do was replace

const router = require('express').Router();

with

import express from 'express';
const router = express.Router();

Solution 14 - Typescript

In my case I was using angular and I was trying to assign a variable in a method with colon instead of equal, like this:

const user$ : this.service.getUser();

It should've been:

const user$ = this.service.getUser();

Solution 15 - Typescript

another solution namespace

> IIFE function & closure

demo.ts

// 1. namespace function
namespace a {
  const func = () => {
    //
  }
}

// 2. function
const test = () => {
  //
}

demo.js


"use strict";
// 1. namespace function
var a;
(function (a) {
    const func = () => {
        //
    };
})(a || (a = {}));

// 2. function
const test = () => {
    //
};

refs

https://www.typescriptlang.org/docs/handbook/namespaces.html

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

Solution 16 - Typescript

In my case refactor to use namespace solved most issues

enter image description here

Solution 17 - Typescript

just add the below line in TSconfig file

"compilerOptions": { "skipLibCheck": true }

Solution 18 - Typescript

The simplest solution is to change the:

"target": "es5" to "target": "es6" at tsconfig.json file.

If you cannot access this file just run:

tsc --init in the main directory.

Because initially the typescript will be sat to JavaScript es5 and that cannot understand the latest JavaScript syntax.

Solution 19 - Typescript

It happens when variable co is already defined in the scope (maybe window/global object has it) and you are again declaring the variable with the same name.

if you replace let with var then it will not give an error but since you are using let then it is not allowed to re-declare the same variable using let

rename the variable to something else and the error will be gone.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondcsanView Question on Stackoverflow
Solution 1 - TypescriptJohn WeiszView Answer on Stackoverflow
Solution 2 - TypescriptNeville OmangiView Answer on Stackoverflow
Solution 3 - TypescriptObinna NnenanyaView Answer on Stackoverflow
Solution 4 - TypescriptTom MettamView Answer on Stackoverflow
Solution 5 - TypescriptBelterView Answer on Stackoverflow
Solution 6 - TypescriptPaul J DreyerView Answer on Stackoverflow
Solution 7 - TypescriptbmaupinView Answer on Stackoverflow
Solution 8 - TypescriptTran Son HoangView Answer on Stackoverflow
Solution 9 - TypescriptDanielView Answer on Stackoverflow
Solution 10 - Typescriptuser17992667View Answer on Stackoverflow
Solution 11 - Typescriptdjango devView Answer on Stackoverflow
Solution 12 - TypescriptChrisView Answer on Stackoverflow
Solution 13 - Typescriptanosha_rehanView Answer on Stackoverflow
Solution 14 - TypescriptCatalin PirvuView Answer on Stackoverflow
Solution 15 - TypescriptxgqfrmsView Answer on Stackoverflow
Solution 16 - TypescriptSkorpENView Answer on Stackoverflow
Solution 17 - TypescriptRahul VanaveView Answer on Stackoverflow
Solution 18 - TypescriptMohammedView Answer on Stackoverflow
Solution 19 - TypescriptJayesh ChoudharyView Answer on Stackoverflow