241

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?

4
  • 1
    How about this - let co_module = require("co"); I faced something similar and this solved the error.
    – tyrion
    Apr 25, 2016 at 9:58
  • 2
    This seems to be a typescript bug. I've made a minimal example here: gist.github.com/rjmunro/428ec644b6e53a499ca3a5ba8de2edc7
    – rjmunro
    Jan 18, 2017 at 11:00
  • 34
    2.5 years later and I'm back at my own question, this is still a problem. this time with node built ins. const fs = require('fs') gives similar error so not sure what library to import this from...
    – dcsan
    Aug 6, 2018 at 15:55
  • 18
    The fact TS still does this is ridiculous
    – GN.
    Sep 23, 2020 at 18:48

21 Answers 21

167

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

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"]
      }
}
5
  • 1
    this is for client side? my original problem was with server side code and I don't believe the DOM compiler options were being used (old project)
    – dcsan
    Feb 11, 2019 at 4:27
  • 24
    I confirm that adding export {} did solve the problem to me, however adding "compilerOptions": { "lib": ["es6"] } does NOT seem to help neither during compilation neither in VSCode. Aug 12, 2020 at 16:00
  • 4
    This solved my issue, but I wonder what were the reasons they had to take such a decision. I don't have a problem adding export {} on a file, but if I'd had some 30 files that would be annoying.
    – ncardez
    Jun 28, 2021 at 21:19
  • the 3rd solution resolved a different issue raised when using DOM reserved names (which by the suggested practice omits the DOM typings). it doesn't resolve the issue raised here
    – Yinon
    Oct 12, 2022 at 10:06
  • If you use import in stead of require to import the module it we dont need to do anything
    – cb_dev
    Oct 20, 2023 at 0:59
98

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;
}
6
  • 10
    this gives "cannot find module co". I also tried typings install co which gives Unable to find "co" in the registry. any other ideas?
    – dcsan
    Mar 3, 2016 at 6:34
  • I'm having the same issue as @dcsan it says it can't find the module even though I clearly have it npm installed. May 16, 2016 at 21:32
  • 2
    be attentive, "* as xxx" is important. So, not "import xxx from ..." but "import * as xxx from ..." May 30, 2018 at 9:52
  • 2
    I was not able to use imports in my nodejs app until I added this to my tsconfig.json:"module": "commonjs"
    – JBaczuk
    Jan 20, 2021 at 22:03
  • 1
    > 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. That solved the issue I was experiencing. Apr 15, 2022 at 17:28
64

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

2
  • what about files with existing exports
    – Siva Tumma
    Mar 17, 2023 at 14:57
  • It doesn't matter the content of the file, adding the empty import at the top fixes the issue Mar 18, 2023 at 15:35
31

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.

2
  • 4
    A great answer that solves the problem, thanks! The error takes place only when both .ts and .js files are opened in Vscode simultaneousely, and after closing a .js file the problem is gone. Jul 14, 2021 at 18:46
  • This answer isn't relevant for those getting the error from the ts compiler
    – Andy Ray
    Oct 2, 2021 at 0:44
20

This is solved via "moduleDetection": "force" in your tsconfig.json:

{
  "compilerOptions": {
    "moduleDetection": "force"
  }
}   

Reference: https://www.typescriptlang.org/tsconfig#moduleDetection

Original anwser: https://stackoverflow.com/a/74968079/10538886

1
  • best and clean answer, if this option does not have some other implication!
    – Magico
    Jan 23 at 22:43
15

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"]
}
0
14

Use IIFE(Immediately Invoked Function Expression), IIFE

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

 })();
2
  • Simple. Works perfectly. Thank you! (In my case, I was declaring const expect = chai.expect; in order to use Cucumber tests in Angular 5 project).
    – Maxime
    Feb 22, 2018 at 12:46
  • when working with coding UI tooling definitely the simplest solution
    – ncubica
    Jun 2, 2022 at 18:44
8

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

0
8

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.

0
3

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.

1
  • 2
    Even though you made the no-no of posting code in images, replacing my module.exports with export ... removed the error for me.
    – Andy Ray
    Oct 2, 2021 at 0:45
2

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.

2

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();
1
  • I had to upgrade express to the latest version to get this to work, a small patch-update fixed a couple errors I had. Including, default not a function, and express not a function
    – SeanMC
    Feb 11, 2022 at 13:46
1

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.

1
  • 7
    Just in case anyone is put off TypeScript by the verbosity and repetitiveness of that gulp file, no one does this. Mar 1, 2017 at 8:35
1

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

1
  • 1
    Same thing for WebStorm 2020.3. The hint that this was the right solution is that it was working before and the error started to appear after some apparently unrelated actions (e.g. unrelated changes commit, push, etc)
    – Ricardo
    Aug 26, 2021 at 18:02
0

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.

0

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();

0

In my case refactor to use namespace solved most issues

enter image description here

0

So... I did something, and it seemed to solve the problem, but I'm not really sure of unseen consequences, but it seems really simple.

I just put { at the start of the file and } at the end, therefore making a new block in the file...

file1.ts

{
  let co=require('co');
  //...
  module.exports=...
}

file2.ts

let co=require('co');
let f1=require('./file1');
//...
module.exports=...
0

I suggest you use the ES6 import and that should fix the issue. Make sure your tsconfig file is like the following:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "outDir": "./build",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

you can change the "outDir" and the "include" based on your own folder structure.

-1

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.

-2

working on today's date: 12/22

example:

 button const =() {}
 export default button;

 export const button2(){}
        

--------------Import------------

import button, {ButtonIcon} from '../Button';
2
  • Please write your answers in English and according to How to Answer. What do you mean by "12/22"? Please take the the tour.
    – Yunnosch
    Dec 2, 2022 at 23:28
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Ethan
    Dec 3, 2022 at 22:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.