无法重新声明块作用域变量
Cannot redeclare block scoped variable
我正在构建一个节点应用程序,并且在 .js 中的每个文件中用于在各种包中执行此操作。
let co = require("co");
但是得到
等所以使用打字稿似乎整个项目中只能有一个这样的 declaration/require ?
我对此感到困惑,因为我认为 let
的范围仅限于当前文件。
我刚刚有一个工作正常的项目,但在重构之后我现在到处都是这些错误。
谁能解释一下?
关于错误本身,let
用于声明存在于block scopes中的局部变量而不是函数作用域。它也比 var
更严格,所以你不能做这样的事情:
if (condition) {
let a = 1;
...
let a = 2;
}
另请注意,switch
块内的 case
子句不会创建自己的块作用域,因此您不能在多个 case
中重新声明同一个局部变量而不使用{}
每人创建一个区块。
至于导入,您可能会收到此错误,因为 TypeScript 无法将您的文件识别为实际模块,并且看似模型级的定义最终成为它的全局定义。
尝试以标准 ES6 方式导入外部模块,其中不包含明确的分配,并且应该使 TypeScript 将您的文件正确识别为模块:
import * as co from "./co"
如果你已经有了名为 co
的东西,这仍然会导致编译错误,正如预期的那样。例如,这将是一个错误:
import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;
如果您遇到错误 "cannot find module co"...
TypeScript 是 运行 针对模块的完整类型检查,因此如果您没有要导入的模块的 TS 定义(例如,因为它是一个没有定义文件的 JS 模块),您可以在不包含模块级导出的 .d.ts
定义文件中声明 您的模块:
declare module "co" {
declare var co: any;
export = co;
}
我遇到了同样的问题,我的解决方案是这样的:
// *./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();
}
}
}
现在我们可以在服务端使用了:
// *./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());
在客户端也是如此:
// *./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
当然,所有这些的 gulp 文件:
// *./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);
})
已更新。
当然,不一定要单独编译打字稿文件。
runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback)
完美。
使用IIFE(Immediately Invoked Function Expression)
、IIFE
(function () {
all your code is here...
})();
我能得到的最好的解释来自 Tamas Piro's post。
TLDR;
TypeScript 对全局执行环境使用 DOM 类型。在您的情况下,全局 window 对象上有一个 'co' 属性。
解决这个问题:
重命名变量,或
使用 TypeScript 模块,并添加一个空导出{}:
export {};
或
通过不添加 DOM 类型来配置您的编译器选项:
在 TypeScript 项目目录中编辑 tsconfig.json。
{
"compilerOptions": {
"lib": ["es6"]
}
}
我在编译我的 Node.JS Typescript 应用程序时收到类似的错误:
node_modules/@types/node/index.d.ts:83:15 - error TS2451: Cannot redeclare block-scoped variable 'custom'.
解决方法是删除这个:
"files": [
"./node_modules/@types/node/index.d.ts"
]
并将其替换为:
"compilerOptions": {
"types": ["node"]
}
对于这个时代来到这里的人,这里有一个解决这个问题的简单方法。它至少在后端对我有用。我还没有检查前端代码。
只需添加:
export {};
在所有没有现有导出代码的文件的顶部。
在我的案例中,以下 tsconfig.json
解决了问题:
{
"compilerOptions": {
"esModuleInterop": true,
"target": "ES2020",
"moduleResolution": "node"
}
}
在package.json
中应该没有type
:module
。
在我的例子中(使用 IntelliJ)File
- Invalidate Caches / Restart...
成功了。
这是我针对我的情况的解决方法。简单快捷!!!
当块作用域变量在源代码中的某处声明时会发生这种情况。
要解决此问题,请删除 module.exports =
并替换为 export default
。
只需在 TSconfig 文件中添加以下行
“编译器选项”:{
"skipLibCheck": true
}
我在 vscode 上使用 ts 时也处理过这个问题。我解决这个问题的方法很简单,但它可能与你的问题不一样。
当我在最近的选项卡中同时打开打字稿文件和 javascript 文件时,我的编辑器显示此错误。我只是关闭它,错误消失了。
希望这对那些可能也因这个简单的错误而摸不着头脑的人有所帮助。
最简单的解决方案是更改:
"target": "es5"
到 "target": "es6"
在 tsconfig.json
文件。
如果您无法访问此文件 运行:
tsc --init
在主目录中。
因为最初 typescript 将被设置为 JavaScript es5 并且无法理解最新的 JavaScript 语法。
当变量 co 已经在作用域中定义(也许 window/global 对象有它)并且您再次声明同名变量时会发生这种情况。
如果您将 let 替换为 var 那么它不会报错,但是由于您使用的是 let ,因此不允许使用 let
重新声明相同的变量
将变量重命名为其他名称,错误将消失。
我的解决方案是将我的代码从使用 CommonJS(require
、module.exports
等)转换为 ES 模块(import
、export
等)。 )
TypeScript 文档似乎也推荐 ES 模块语法:TypeScript Modules
当然还有很多,但作为一个开始:
将 require
的实例替换为 import
,例如
替换:
const https = require('https');
有:
import https from 'https';
将默认的module.exports
替换为export default
,例如
替换:
module.exports = myVar ...
有:
export default myVar ...
将其他module.exports
替换为export
,例如
替换:
module.exports.myVar =
或:
module.export = { myVar ... }
有:
export myVar ...
更多信息:From CommonJS to ES Modules: How to modernize your Node.js app
这是编辑器警告,因为当您打开 index.js 时,它已编译并且 index.ts。你会看到这个..但是当你关闭 index.js 就没问题了。
我在错误地导入 express
时遇到了类似的错误。
我所要做的就是替换
const router = require('express').Router();
和
import express from 'express';
const router = express.Router();
在我的例子中,我使用的是 angular 并且我试图在方法中使用冒号而不是等号来分配变量,如下所示:
const user$ : this.service.getUser();
应该是:
const user$ = this.service.getUser();
另一个解决方案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 = () => {
//
};
参考资料
https://www.typescriptlang.org/docs/handbook/namespaces.html
https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html
在我的案例中,使用命名空间重构解决了大部分问题
我正在构建一个节点应用程序,并且在 .js 中的每个文件中用于在各种包中执行此操作。
let co = require("co");
但是得到
等所以使用打字稿似乎整个项目中只能有一个这样的 declaration/require ?
我对此感到困惑,因为我认为 let
的范围仅限于当前文件。
我刚刚有一个工作正常的项目,但在重构之后我现在到处都是这些错误。
谁能解释一下?
关于错误本身,let
用于声明存在于block scopes中的局部变量而不是函数作用域。它也比 var
更严格,所以你不能做这样的事情:
if (condition) {
let a = 1;
...
let a = 2;
}
另请注意,switch
块内的 case
子句不会创建自己的块作用域,因此您不能在多个 case
中重新声明同一个局部变量而不使用{}
每人创建一个区块。
至于导入,您可能会收到此错误,因为 TypeScript 无法将您的文件识别为实际模块,并且看似模型级的定义最终成为它的全局定义。
尝试以标准 ES6 方式导入外部模块,其中不包含明确的分配,并且应该使 TypeScript 将您的文件正确识别为模块:
import * as co from "./co"
如果你已经有了名为 co
的东西,这仍然会导致编译错误,正如预期的那样。例如,这将是一个错误:
import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;
如果您遇到错误 "cannot find module co"...
TypeScript 是 运行 针对模块的完整类型检查,因此如果您没有要导入的模块的 TS 定义(例如,因为它是一个没有定义文件的 JS 模块),您可以在不包含模块级导出的 .d.ts
定义文件中声明 您的模块:
declare module "co" {
declare var co: any;
export = co;
}
我遇到了同样的问题,我的解决方案是这样的:
// *./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();
}
}
}
现在我们可以在服务端使用了:
// *./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());
在客户端也是如此:
// *./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
当然,所有这些的 gulp 文件:
// *./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);
})
已更新。
当然,不一定要单独编译打字稿文件。
runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback)
完美。
使用IIFE(Immediately Invoked Function Expression)
、IIFE
(function () {
all your code is here...
})();
我能得到的最好的解释来自 Tamas Piro's post。
TLDR; TypeScript 对全局执行环境使用 DOM 类型。在您的情况下,全局 window 对象上有一个 'co' 属性。
解决这个问题:
重命名变量,或
使用 TypeScript 模块,并添加一个空导出{}:
export {};
或
通过不添加 DOM 类型来配置您的编译器选项:
在 TypeScript 项目目录中编辑 tsconfig.json。
{
"compilerOptions": {
"lib": ["es6"]
}
}
我在编译我的 Node.JS Typescript 应用程序时收到类似的错误:
node_modules/@types/node/index.d.ts:83:15 - error TS2451: Cannot redeclare block-scoped variable 'custom'.
解决方法是删除这个:
"files": [
"./node_modules/@types/node/index.d.ts"
]
并将其替换为:
"compilerOptions": {
"types": ["node"]
}
对于这个时代来到这里的人,这里有一个解决这个问题的简单方法。它至少在后端对我有用。我还没有检查前端代码。
只需添加:
export {};
在所有没有现有导出代码的文件的顶部。
在我的案例中,以下 tsconfig.json
解决了问题:
{
"compilerOptions": {
"esModuleInterop": true,
"target": "ES2020",
"moduleResolution": "node"
}
}
在package.json
中应该没有type
:module
。
在我的例子中(使用 IntelliJ)File
- Invalidate Caches / Restart...
成功了。
这是我针对我的情况的解决方法。简单快捷!!!
当块作用域变量在源代码中的某处声明时会发生这种情况。
要解决此问题,请删除 module.exports =
并替换为 export default
。
只需在 TSconfig 文件中添加以下行
“编译器选项”:{ "skipLibCheck": true }
我在 vscode 上使用 ts 时也处理过这个问题。我解决这个问题的方法很简单,但它可能与你的问题不一样。
当我在最近的选项卡中同时打开打字稿文件和 javascript 文件时,我的编辑器显示此错误。我只是关闭它,错误消失了。
希望这对那些可能也因这个简单的错误而摸不着头脑的人有所帮助。
最简单的解决方案是更改:
"target": "es5"
到 "target": "es6"
在 tsconfig.json
文件。
如果您无法访问此文件 运行:
tsc --init
在主目录中。
因为最初 typescript 将被设置为 JavaScript es5 并且无法理解最新的 JavaScript 语法。
当变量 co 已经在作用域中定义(也许 window/global 对象有它)并且您再次声明同名变量时会发生这种情况。
如果您将 let 替换为 var 那么它不会报错,但是由于您使用的是 let ,因此不允许使用 let
重新声明相同的变量将变量重命名为其他名称,错误将消失。
我的解决方案是将我的代码从使用 CommonJS(require
、module.exports
等)转换为 ES 模块(import
、export
等)。 )
TypeScript 文档似乎也推荐 ES 模块语法:TypeScript Modules
当然还有很多,但作为一个开始:
将
require
的实例替换为import
,例如替换:
const https = require('https');
有:
import https from 'https';
将默认的
module.exports
替换为export default
,例如替换:
module.exports = myVar ...
有:
export default myVar ...
将其他
module.exports
替换为export
,例如替换:
module.exports.myVar =
或:
module.export = { myVar ... }
有:
export myVar ...
更多信息:From CommonJS to ES Modules: How to modernize your Node.js app
这是编辑器警告,因为当您打开 index.js 时,它已编译并且 index.ts。你会看到这个..但是当你关闭 index.js 就没问题了。
我在错误地导入 express
时遇到了类似的错误。
我所要做的就是替换
const router = require('express').Router();
和
import express from 'express';
const router = express.Router();
在我的例子中,我使用的是 angular 并且我试图在方法中使用冒号而不是等号来分配变量,如下所示:
const user$ : this.service.getUser();
应该是:
const user$ = this.service.getUser();
另一个解决方案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 = () => {
//
};
参考资料
https://www.typescriptlang.org/docs/handbook/namespaces.html
https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html
在我的案例中,使用命名空间重构解决了大部分问题