背景

当使用 TypeScript + TSlint + Babel + Jest 搭建开发环境时,在开发过程中偶尔会被 IDE 提示「无法重新声明块范围变量」,从而导致编译出错,报错图示如下:

相关开发环境配置如下:

  • typescript: ^3.5.3
  • tslint: ^5.19.0
  • babel: ^7.0.0
  • jest: ^24.9.0
  • ts-jest: ^24.0.2

解决方案

之所以 tslint 会提示这个错误,是因为在 Commonjs 规范里,没有像 ESModule 能形成闭包的「模块」概念,所有的模块在引用时都默认被抛至全局,因此当再次声明某个模块时,TypeScript 会认为重复声明了两次相同的变量进而抛错。

对于这个问题,最简单的解决方法是在报错的文件底部添加一行代码:export {}。这行代码会「欺骗」tslint 使其认为当前文件是一个 ESModule 模块,因此不存在变量重复声明的可能性。当使用这个方法时,记得这样配置你的 tsconfig.json 文件:

{
"include": ["src", "demo"],
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"esModuleInterop": true, // important!
"target": "esnext",
"strict": true,
"outDir": "app",
"declaration": true,
"sourceMap": true
}
}

其中 esMoudleInterop 这个配置允许文件中出现 export 关键字。

问题 2

当你以为已经万事大吉的时候,你会发现第二个问题又浮出水面:你无法执行编译后的 JavaScript 代码!是的,因为 babel 虽然能够帮你成功转译了 TypeScript 代码,但是并没有帮你去掉,你 hack 上的 export 关键字,因此 node 会由于无法识别该关键字而报错。

此时你有两个选择:

删除 export 关键字,忍受恼人的 IDE 提示,强行让 babel 编译;

幸运的是,这样做真的行得通,因为 tslint 只是一个 “lint”,它只负责提示你哪里有问题,你可以强行忽略它。但是,当你使用 Jest 配合 TypeScript 进行测试时这样做就行不通了,因为 Jest 会把 tslint 发现的错误当成无法原谅的错误告诉你,这意味着,你别想开开心心的测试你的代码,当然你还可以选择第二种解法:

写一个 babel 插件,让 babel 转译时去除 export 关键字;

这样你的 node 可以识别转译后的代码,你的 Jest 也不再会抱怨什么,两全其美!然而,你真的想要专门为此写一个插件吗?

如果你的第一反应和我一样是脑海中一个大大的 「NO!!!」,你应该继续往下看了,其实我们还有第三个方案:)

终极解决方案

实际上,已经有一个 babel 插件可以满足我们得需求了:@babel/plugin-transform-modules-commonjs ,这就是我们一直梦寐以求的东西。正如插件名所暗示的,它可以将 ESModule 模块转换为符合 Commonjs 规范的代码,而经过我的测试,当遇到 export {} 这样的表达式时,其转译的方案是:「直接忽略」!这正是我们想要的效果!

就这样,在你的 babel.config.js 中加入这个插件,TSlint 不会再抱怨什么,Jest 能够乖乖测试,Node 也不会朝你大吼 "What the * export !!",整个世界都清净了。

最后,再分享一下我的全套相关配置,希望你们不再为这个问题感到困扰

彻底解决 TypeScript 报错:“无法重新声明块范围变量”的问题的更多相关文章

  1. react+typescript报错集锦<持续更新>

    typescript报错集锦 错误:Import sources within a group must be alphabetized.tslint(ordered-imports) 原因:impo ...

  2. Idea使用记录--添加Problems&&解决Autowired报错could not autowire

    今天在使用Idea的时候,发现Idea在整个每次找到错误代码非常不方便(Idea如果类中有错误,没有打开过类并不会提示,比如构建工程后缺少jar包问题).我想快速看到工程哪里出问题类似于eclipse ...

  3. [转]解决Maven报错"Plugin execution not covered by lifecycle configuration"

    [转]解决Maven报错"Plugin execution not covered by lifecycle configuration" 导入Myabtis源码后,POM文件会报 ...

  4. 解决MySQL报错ERROR 2002 (HY000)【转】

    今天在为新的业务线搭架数据库后,在启动的时候报错 root@qsbilldatahis-db01:/usr/local/mysql/bin# ./mysql ERROR 2002 (HY000): C ...

  5. vue解决启动报错cjs loader.js Error: Cannot find module '../config'问题

    vue解决启动报错cjs loader.js Error: Cannot find module '../config'问题 今天下载了一个开源项目一直运行不了,折腾了半天才找到问题所在,config ...

  6. 解决 php 报错 open_basedir restriction in effect或者nginx提示No input file specified怎么办

    解决 php 报错 open_basedir restriction in effect或者nginx提示No input file specified怎么办 问题是出现在了PHP.INI上面了 ,原 ...

  7. 解决MySQL报错:1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'informat

    解决MySQL报错:1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'informat ...

  8. eclips中maven解决jsp报错的问题

    加入如下的pom依赖: <!-- 解决jsp报错的依赖包第一个 --> <dependency> <groupId>javax.servlet</groupI ...

  9. 不修改系统日期和时间格式,解决Delphi报错提示 '****-**-**'is not a valid date and time

    假如操作系统的日期格式不是yyyy-MM-dd格式,而是用strtodate('2014-10-01')) 来转换的话,程序会提示爆粗 '****-**-**'is not a valid date ...

随机推荐

  1. C# 给某个方法设定执行超时时间-2

    var response = RunTaskWithTimeout<ReturnType>( (Func<ReturnType>)); /// <summary> ...

  2. 诺依/RuoYi开源系统搭建总结

    问题一:从{码云}下载下来看,输入项目编码不过 解决方法: 加入下列依赖,版本要和下载下来的{spring-boot-dependencies}一致.不一致就会报问题2: <parent> ...

  3. UI自动化关于图片验证码识别的解决方法

    def __save_screenshot(self): self.driver.save_screenshot('full_snap.png') self.page_snap_obj = Image ...

  4. Linux 常用命令之 mv cp scp

    1.mv 命令是move的缩写,用于文件(或文件夹)移动的. 1)将 luna 目录下的文件 a.txt,移动到 miracle 目录下: mv ./luna/a.txt ./miracle/ 2)将 ...

  5. MySQL 5.7.27 MGR 单主/多主+ ProxySQL

    1 MySQL 5.7.27 MGR 多主环境 基础信息如下: centos 6.5/vbox 实例名 A B C IP 10.15.7.29 10.15.7.28 10.15.7.27 实例端口号 ...

  6. CSS3 —— 文本 背景 列表 渐变

    <span>标签 作用 ——  能让某几个文字或者某个词语凸显出来 候选字体 p {font-family: Times, TimesNR, 'New Century Schoolbook ...

  7. 写一个比较全的进制转换函数--ic

    //写一个比较全的进制转换函数-----未完成 #include <stdio.h> //D进制转换后 (比如10-2进制) 结果可能会很大 需要很长的字符串来存 #include < ...

  8. yum本地源和网络源的配置

    一.yum本地源 1. 删除YUM库[root@tianyun ~]# rm    -rf    /etc/yum.repos.d/* 2.挂载安装光盘(临时):[root@tianyun ~]# m ...

  9. 【Qt开发】在QLabel已经显示背景图片后绘制图形注意事项

    主要是要解决图形覆盖的问题,通常的办法就是对QLabel进行子类化,并重载函数: void myLabel::paintEvent(QPaintEvent *event)   {       QLab ...

  10. linux 更改文件权限命令 chmod

    chmod -change file mode bits :更改文件权限 chmod是用来改变文件或者目录权限的命令,但只有文件的属主和超级用户(root)才有这种权限. 更改文件权限的2种方式: 一 ...