224

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?

pppery
  • 3,731
  • 22
  • 33
  • 46
dcsan
  • 11,333
  • 15
  • 77
  • 118

21 Answers21

147

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"]
      }
}
karel
  • 5,489
  • 46
  • 45
  • 50
aphilas
  • 2,066
  • 1
  • 14
  • 9
  • 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 '19 at 04:27
  • 21
    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. – adamsfamily Aug 12 '20 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 '21 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 '22 at 10:06
96

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;
}
John Weisz
  • 30,137
  • 13
  • 89
  • 132
  • 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 03 '16 at 06: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. – justin.m.chase May 16 '16 at 21:32
  • It might be caused by the relative path. I'm not familiar with NodeJS module management, but in RequireJS if modules are referenced relatively, the current folder must be explicitly denoted. That is, `./co` instead of `co`, if co.ts is in the same folder (or the compiled output, co.js). – John Weisz May 17 '16 at 08:08
  • 2
    be attentive, "* as xxx" is important. So, not "import xxx from ..." but "import * as xxx from ..." – Nurbol Alpysbayev May 30 '18 at 09:52
  • 1
    I was not able to use imports in my nodejs app until I added this to my `tsconfig.json`:`"module": "commonjs"` – JBaczuk Jan 20 '21 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. – fourpastmidnight Apr 15 '22 at 17:28
55

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

Marc
  • 13,011
  • 11
  • 78
  • 98
Obinna Nnenanya
  • 1,530
  • 14
  • 15
25

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.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Paul J Dreyer
  • 259
  • 3
  • 2
  • 2
    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. – Roman Karagodin Jul 14 '21 at 18:46
  • This answer isn't relevant for those getting the error from the ts compiler – Andy Ray Oct 02 '21 at 00:44
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"]
}
Tom Mettam
  • 2,903
  • 1
  • 27
  • 38
14

Use IIFE(Immediately Invoked Function Expression), IIFE

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

 })();
Belter
  • 3,573
  • 5
  • 42
  • 58
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

bmaupin
  • 14,427
  • 5
  • 89
  • 94
7

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.

user17992667
  • 79
  • 1
  • 1
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.

Hoang Subin
  • 6,610
  • 6
  • 37
  • 56
  • 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 02 '21 at 00: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.

Daniel
  • 7,684
  • 7
  • 52
  • 76
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();
anosha_rehan
  • 1,522
  • 10
  • 17
  • 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 '22 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.

django dev
  • 36
  • 3
1

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

Chris
  • 4,212
  • 5
  • 37
  • 52
  • 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 '21 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.

Mohammed
  • 163
  • 1
  • 3
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();

Catalin Pirvu
  • 175
  • 2
  • 8
0

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

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
0

In my case refactor to use namespace solved most issues

enter image description here

SkorpEN
  • 2,491
  • 1
  • 22
  • 28
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=...
mZm
  • 136
  • 7
0

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

倪俊杰
  • 56
  • 3
-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';
4b0
  • 21,981
  • 30
  • 95
  • 142
  • Please write your answers in English and according to [answer]. What do you mean by "12/22"? Please take the the [tour]. – Yunnosch Dec 02 '22 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](https://stackoverflow.com/help/how-to-answer). – Ethan Dec 03 '22 at 22:39