为什么Typescript;无法重新声明块作用域变量";?

为什么Typescript;无法重新声明块作用域变量";?,typescript,Typescript,我见过一些黑客让错误信息消失 但我的问题是为什么TS会这样做 这样做的理由和目的是什么?我预计一种语言会希望UTIL库导入多个文件,因此不会认为它是一个“重新声明”。 const uuid=require('uuid/v4') 另一个文件执行相同的导入 无法重新声明块作用域变量“uuid” 我可以在模块a中有一个const foo='123',然后在模块B中重新声明一个const foo='123',没有问题 因为模块的作用域是有限的 为什么导入/要求的行为不同 是什么代码导致这种情况发生的?

我见过一些黑客让错误信息消失

但我的问题是为什么TS会这样做

这样做的理由和目的是什么?我预计一种语言会希望UTIL库导入多个文件,因此不会认为它是一个“重新声明”。
const uuid=require('uuid/v4')

另一个文件执行相同的导入

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

我可以在模块a中有一个
const foo='123'
,然后在模块B中重新声明一个
const foo='123'
,没有问题

因为模块的作用域是有限的

为什么导入/要求的行为不同

是什么代码导致这种情况发生的?

// utils.ts
const uuid = require('uuid/v4');
module.exports = function Utils() { ....}
.......
就是这样,只有两个导入相同的文件

这是TSConfig

{
  "compilerOptions": {
    // * ===================================================================== *
    // * Basic Options
    // * ===================================================================== *
    "allowJs": true,
    "checkJs": true,
    "target": "ES2020",
    "noEmit": true,
    "pretty": true,
    "noErrorTruncation": true,
    "skipLibCheck": true,
    "jsx": "react",

    // * ===================================================================== *
    // * Strict Type-Checking Options
    // * ===================================================================== *
    "noImplicitAny": false, // disabling for now while converting the existing js code, too many errors otherwise
    // "strictNullChecks": false,
    // "noImplicitThis": false,

    // * ===================================================================== *
    // * Additional Checks
    // * ===================================================================== *
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    // * ===================================================================== *
    // * Module Resolution Options
    // * ===================================================================== *
    "module": "commonjs",
    // "moduleResolution": "node",
    "baseUrl": ".",
    "paths": {
      "~actions/*": ["client/javascripts/state/actions/*"],
      "~components/*": ["client/javascripts/components/*"],
      "~constants/*": ["constants/*"],
      "~server/*": ["server/*"],
      "~client/*": ["client/*"],
      "~shared/*": ["shared/*"],
      "~state/*": ["client/javascripts/state/*"],
      "~utils/*": ["client/javascripts/utils/*"],
    },
    "esModuleInterop": true,
    "resolveJsonModule": true,

    // * ===================================================================== *
    // * Source Map Options
    // * ===================================================================== *
    "sourceMap": true,

    // * ===================================================================== *
    // * Experimental Options
    // * ===================================================================== *
    "experimentalDecorators": true,
  },

  "compileOnSave": false,

  "include": [
    "typings/**/*.d.ts",
    "./client/javascripts/**/*.js",
    "./client/javascripts/**/*.jsx",
    "./client/javascripts/**/*.ts",
    "./client/javascripts/**/*.tsx",
    "./constants/**/*.js",
    "./constants/**/*.ts",
    "./constants/**/*.json",
    "./server/**/*.js",
    "./server/**/*.ts",
    "./shared/**/*.js",
    "./shared/**/*.ts",
  ],

  "exclude": [
    "build",
    "coverage",
    "cypress",
    "dist",
    "locales",
    "node_modules",
    "tests",
  ],
}


TypeScript是ECMAScript/JavaScript的超集。ECMAScript不允许重新声明块作用域变量(
const
let
),因此TypeScript也不允许它

<>实际上,对于大多数显式声明块范围变量:C,C++,爪哇,C,您可以这样命名的大多数编程语言是正确的。 C#甚至更进一步:甚至不能在嵌套块中对块范围的变量进行阴影处理

使用两个单独的模块时,我无法再现您的问题:

//utils.ts
从“uuid/v4”导入uuid;
导出函数Utils(){/*…*/}
//import-helper.ts
从“uuid/v4”导入uuid;
导出函数Helper(){/*…*/}
我可以在使用脚本而不是模块时复制它,因为脚本没有单独的作用域:

//utils.ts
const uuid=require('uuid/v4');
module.exports=函数Utils(){/*…*/}
//import-helper.ts
const uuid=require('uuid/v4');
module.exports=函数Helper(){/*…*/}
模块成为模块的原因在(粗体重点部分中进行了解释:

在TypeScript中,就像在ECMAScript 2015中一样,任何包含顶级
导入
导出
的文件都被视为一个模块。相反,没有任何顶级
导入
导出
声明的文件被视为脚本,其内容在全局范围内可用(因此也适用于模块)


ECMAScript虽然在这里不相关,但与此类似。不幸的是,ECMA-262没有像TypeScript手册那样清楚地说明差异,您必须找出所有可能的合法和非法语法来找出差异。但是,由于这里的错误是一个TypeScript错误,因此ECMAScript实际上并不相关。

您误解了错误消息。这是因为您多次导入了一个库。正如它实际上所说的,您正试图用相同的名称重新声明一个
let
const
变量。例如,
const uuid=1;常数uuid=2。请参阅错误消息-它应该说明重新声明发生的位置-您在同一作用域中有另一个共享相同名称的变量。是的,但模块是有作用域的。模块一中可以有一个
const foo=123
,模块二中可以有一个
const foo=123
。检查跨模块的重新声明是没有意义的。我希望看到这个问题的详细情况,因为如果发生这种情况,就真的出了问题。我的假设是您无意中复制/粘贴了某行。@GN<代码>是,但模块的作用域是有限的。
您确定已创建模块吗?您向我们展示的代码行使用的是
require
,而不是
import
不,它们不是。如注释中所述,文件是一个模块,IFF,并且仅当它至少包含
导入
导出
声明时。引用您回复的评论:“我不是指
module.exports
”。是的,但模块的作用域是有限的。模块一中可以有一个
const foo=123
,模块二中可以有一个
const foo=123
。当然,检查跨模块的重新声明毫无意义。但这与此无关。我们讨论的是在同一个块中重新声明一个变量,但我没有这样做。我每个模块/文件只有一个
const-uuid=require('uuid/v4')
。“我每个模块/文件只有一个
const-uuid=require('uuid/v4')
”–是哪个?模块还是文件?这不是一回事。哈哈。单词
const uuid=require('uuid/v4')
仅在每个文件中出现一次。
{
  "compilerOptions": {
    // * ===================================================================== *
    // * Basic Options
    // * ===================================================================== *
    "allowJs": true,
    "checkJs": true,
    "target": "ES2020",
    "noEmit": true,
    "pretty": true,
    "noErrorTruncation": true,
    "skipLibCheck": true,
    "jsx": "react",

    // * ===================================================================== *
    // * Strict Type-Checking Options
    // * ===================================================================== *
    "noImplicitAny": false, // disabling for now while converting the existing js code, too many errors otherwise
    // "strictNullChecks": false,
    // "noImplicitThis": false,

    // * ===================================================================== *
    // * Additional Checks
    // * ===================================================================== *
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    // * ===================================================================== *
    // * Module Resolution Options
    // * ===================================================================== *
    "module": "commonjs",
    // "moduleResolution": "node",
    "baseUrl": ".",
    "paths": {
      "~actions/*": ["client/javascripts/state/actions/*"],
      "~components/*": ["client/javascripts/components/*"],
      "~constants/*": ["constants/*"],
      "~server/*": ["server/*"],
      "~client/*": ["client/*"],
      "~shared/*": ["shared/*"],
      "~state/*": ["client/javascripts/state/*"],
      "~utils/*": ["client/javascripts/utils/*"],
    },
    "esModuleInterop": true,
    "resolveJsonModule": true,

    // * ===================================================================== *
    // * Source Map Options
    // * ===================================================================== *
    "sourceMap": true,

    // * ===================================================================== *
    // * Experimental Options
    // * ===================================================================== *
    "experimentalDecorators": true,
  },

  "compileOnSave": false,

  "include": [
    "typings/**/*.d.ts",
    "./client/javascripts/**/*.js",
    "./client/javascripts/**/*.jsx",
    "./client/javascripts/**/*.ts",
    "./client/javascripts/**/*.tsx",
    "./constants/**/*.js",
    "./constants/**/*.ts",
    "./constants/**/*.json",
    "./server/**/*.js",
    "./server/**/*.ts",
    "./shared/**/*.js",
    "./shared/**/*.ts",
  ],

  "exclude": [
    "build",
    "coverage",
    "cypress",
    "dist",
    "locales",
    "node_modules",
    "tests",
  ],
}