无法重新声明块作用域变量

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' 属性。

解决这个问题:

  1. 重命名变量,或

  2. 使用 TypeScript 模块,并添加一个空导出{}:

    export {};
    

  3. 通过不添加 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 {};

在所有没有现有导出代码的文件的顶部。

归功于 EUGENE MURAVITSKY

在我的案例中,以下 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(requiremodule.exports 等)转换为 ES 模块(importexport 等)。 )

TypeScript 文档似乎也推荐 ES 模块语法:TypeScript Modules

当然还有很多,但作为一个开始:

  1. require 的实例替换为 import,例如

    替换:

    const https = require('https');
    

    有:

    import https from 'https';
    
  2. 将默认的module.exports替换为export default,例如

    替换:

    module.exports = myVar ...
    

    有:

    export default myVar ...
    
  3. 将其他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

在我的案例中,使用命名空间重构解决了大部分问题