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