无法重新声明块范围变量(打字稿)
Posted
技术标签:
【中文标题】无法重新声明块范围变量(打字稿)【英文标题】:Cannot redeclare block scoped variable 【发布时间】:2016-06-15 23:26:26 【问题描述】:我正在构建一个节点应用程序,并且在 .js 中的每个文件中习惯于在各种包中执行此操作。
let co = require("co");
但是得到
等等。所以使用打字稿似乎整个项目只能有一个这样的声明/要求?
我对此感到困惑,因为我认为 let
的范围仅限于当前文件。
我刚刚有一个正在运行的项目,但是在重构之后,现在到处都是这些错误。
谁能解释一下?
【问题讨论】:
这个怎么样 - let co_module = require("co");我遇到了类似的事情,这解决了错误。 这似乎是一个打字稿错误。我在这里做了一个最小的例子:gist.github.com/rjmunro/428ec644b6e53a499ca3a5ba8de2edc7 2.5 年后,我又回到了自己的问题上,这仍然是一个问题。这次使用的是内置节点。const fs = require('fs')
给出了类似的错误,所以不确定要从哪个库导入它...
TS 仍然这样做的事实是荒谬的
@rjmunro 但是你如何解决这个问题?
【参考方案1】:
关于错误本身,let
用于声明存在于block scopes 中的本地 变量,而不是函数范围。它也比var
更严格,所以你不能做这样的事情:
if (condition)
let a = 1;
...
let a = 2;
另请注意,switch
块内的 case
子句不会创建自己的块作用域,因此您不能在不使用 为每个块创建块的情况下跨多个
case
s 重新声明相同的局部变量.
至于导入,您可能会收到此错误,因为 TypeScript 无法将您的文件识别为实际模块,并且看似模型级定义最终成为它的全局定义。
尝试以标准 ES6 方式导入外部模块,其中不包含显式分配,并且应该使 TypeScript 将您的文件正确识别为模块:
import * as co from "./co"
如果您已经有一个名为co
的东西,这仍然会导致编译错误,正如预期的那样。例如,这将是一个错误:
import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;
如果您收到错误“找不到模块合作”...
TypeScript 正在对模块进行完整的类型检查,因此如果您没有尝试导入的模块的 TS 定义(例如,因为它是没有定义文件的 JS 模块),您可以声明 em> 您的模块在不包含模块级导出的 .d.ts
定义文件中:
declare module "co"
declare var co: any;
export = co;
【讨论】:
这给出了“找不到模块 co”。我还尝试了typings install co
,它给出了Unable to find "co" in the registry
。还有其他想法吗?
我遇到了与@dcsan 相同的问题,它说即使我清楚地安装了 npm,它也找不到模块。
可能是相对路径造成的。我对 NodeJS 的模块管理不熟悉,但是在 RequireJS 中,如果相对引用了模块,则必须明确表示当前文件夹。也就是说,./co
而不是 co
,如果 co.ts 在同一个文件夹中(或编译输出,co.js)。
注意,“* as xxx”很重要。所以,不是“import xxx from ...”而是“import * as xxx from ...”
在将其添加到我的 tsconfig.json
:"module": "commonjs"
之前,我无法在我的 nodejs 应用程序中使用导入。【参考方案2】:
我能得到的最好解释来自Tamas Piro's post。
TLDR; TypeScript 将 DOM 类型用于全局执行环境。在您的情况下,全局窗口对象上有一个“co”属性。
解决这个问题:
重命名变量,或
使用 TypeScript 模块,并添加一个空的导出:
export ;
或
通过不添加 DOM 类型来配置编译器选项:
编辑 TypeScript 项目目录中的 tsconfig.json。
"compilerOptions":
"lib": ["es6"]
【讨论】:
这是给客户端的吗?我最初的问题是服务器端代码,我不相信正在使用 DOM 编译器选项(旧项目) 我确认添加export
确实解决了我的问题,但是在编译期间添加 "compilerOptions": "lib": ["es6"]
似乎在 VSCode 中也没有帮助。
原帖链接已失效。
这解决了我的问题,但我想知道他们必须做出这样决定的原因是什么。在文件上添加export
没有问题,但如果我有大约 30 个文件,那会很烦人。
@CyclonecodeCycle 链接现在正常运行【参考方案3】:
对于那些在这个时代来到这里的人,这里有一个解决这个问题的简单方法。它至少在后端对我有用。我没有检查前端代码。
只需添加:
export ;
在代码的顶部。
感谢EUGENE MURAVITSKY
【讨论】:
【参考方案4】:我在编译我的 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"]
【讨论】:
【参考方案5】:使用IIFE(Immediately Invoked Function Expression)
、IIFE
(function ()
all your code is here...
)();
【讨论】:
简单。完美运行。谢谢! (在我的例子中,我声明const expect = chai.expect;
是为了在 Angular 5 项目中使用 Cucumber 测试)。【参考方案6】:
我在 vscode 上使用 ts 时也处理过这个问题。我解决此问题的方法很简单,但可能与您的问题不同。
当我在最近的选项卡中同时打开 typescript 文件和 javascript 文件时,我的编辑器显示此错误。我只是关闭它,错误就消失了。
希望这可以帮助那些可能也因这个简单的错误而摸不着头脑的人。
【讨论】:
解决问题的好答案,谢谢!只有在Vscode中同时打开.ts和.js文件时才会出现错误,关闭.js文件后问题就消失了。 这个答案与那些从 ts 编译器得到错误的人无关【参考方案7】:我的解决方案是将我的代码从使用 CommonJS(require
、module.exports
等)转换为 ES 模块(import
、export
等)
TypeScript 文档似乎也推荐 ES Module 语法: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
【讨论】:
【参考方案8】:这是针对我的情况的解决方法。简单快捷!!!
当块范围的变量在源代码的某处声明时会发生这种情况。
要解决此问题,请删除 module.exports =
并替换为 export default
。
【讨论】:
即使您禁止在图像中发布代码,将我的module.exports
替换为 export ...
为我消除了错误。【参考方案9】:
我遇到了同样的问题,我的解决方案如下所示:
// *./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);
)
已更新。
当然,没有必要单独编译 typescript 文件。
runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback)
完美运行。
【讨论】:
以防万一有人因为那个 gulp 文件的冗长和重复性而对 TypeScript 感到厌烦,没有人会这样做。【参考方案10】:在我的情况下,以下tsconfig.json
解决了问题:
"compilerOptions":
"esModuleInterop": true,
"target": "ES2020",
"moduleResolution": "node"
package.json
中不应有type
: module
。
【讨论】:
【参考方案11】:就我而言(使用 IntelliJ)File
- Invalidate Caches / Restart...
成功了。
【讨论】:
WebStorm 2020.3 也是如此。这是正确解决方案的提示是它之前正在工作,并且在一些明显不相关的操作(例如,不相关的更改提交、推送等)之后开始出现错误【参考方案12】:这是编辑器警告,因为当您打开已编译的 index.js 和 index.ts 时。你会看到这个.. 但是当你关闭 index.js 就可以了。
【讨论】:
正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。【参考方案13】:只需在 TSconfig 文件中添加以下行
“编译器选项”: “skipLibCheck”:真
【讨论】:
该选项与错误无关。我有那个选项,但我仍然收到错误。【参考方案14】:最简单的解决方案是更改:
"target": "es5"
到 "target": "es6"
tsconfig.json
文件。
如果您无法访问此文件,请运行:
tsc --init
在主目录中。
因为最初 typescript 将使用 JavaScript es5 并且无法理解最新的 JavaScript 语法。
【讨论】:
【参考方案15】:当变量 co 已经在作用域中定义(可能是窗口/全局对象有它)并且您再次声明具有相同名称的变量时,就会发生这种情况。
如果你用 var 替换 let,那么它不会报错,但是因为你使用的是 let,所以不允许使用 let 重新声明相同的变量
将变量重命名为其他名称,错误就会消失。
【讨论】:
以上是关于无法重新声明块范围变量(打字稿)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Typescript 2.8 React Native - 无法重新声明块范围变量“控制台”
“无法重新声明块范围的变量”和“SyntaxError:意外的令牌'导出'”[关闭]
如何解决 Testcafe 和 Jest 之间的类型冲突? (“无法重新声明块范围变量'test'”)
彻底解决 TypeScript 报错:“无法重新声明块范围变量”的问题