无法重新声明块范围变量(打字稿)

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 子句不会创建自己的块作用域,因此您不能在不使用 为每个块创建块的情况下跨多个 cases 重新声明相同的局部变量.


至于导入,您可能会收到此错误,因为 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(requiremodule.exports 等)转换为 ES 模块(importexport 等)

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 报错:“无法重新声明块范围变量”的问题

在角度 CLI 中出现构建错误:无法重新声明块范围变量“ngDevMode”

打字稿更改后nodemon没有重新启动