Cannot redeclare block scoped variable
TypescriptRequireTypescript 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
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 case
s 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:
-
Rename the variable, or
-
Use TypeScript modules, and add an empty export{}:
export {};
or
-
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:
-
Replace instances of
require
withimport
, e.g.Replace:
const https = require('https');
With:
import https from 'https';
-
Replace the default
module.exports
withexport default
, e.g.Replace:
module.exports = myVar ...
With:
export default myVar ...
-
Replace other
module.exports
withexport
, 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!!!
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
namespace
another solution > 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
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.