最近写的项目都使用了 ESNext ,ESNext 是一个动态的 ECMAScript 版本,指当前最新发布的版本没有包含,但已经定案、包含新特性的 ECMAScript 版本。
好端端的为什么要使用 ESNext ?
因为我有一些需求,需要在顶级使用 await
表达式。但是 await
表达式是只能包含在 async
函数中,这就导致了很多的不便,再加上这种写法也并非优雅↓
let data = ''
;(
async () => {
data = await sql.query('SELECT * FROM user')
}
)()
那么如果能在顶级使用,那就会非常的好且便利
如果直接使用,ts中会报错
仅当 “module” 选项设置为 “es2022”、“esnext”、“system”、“node16” 或 “nodenext”,且 “target” 选项设置为 “es2017” 或更高版本时,才允许使用顶级 “await” 表达式。ts(1378)
并且在一些特殊的场景必须使用顶级 await
const xxx = await CreateXXX({
xxx: xxx,
xxx: xxx
})
export default xxx
此时如果使用自执行函数会导致无法导出,包括 设置 package.json
的 "type": "module"
等都会报错
在 https://www.alinalihassan.com/blog/top-level-await-typescript 中记载,使用 ESNext 可以使用顶级 await
表达式
将 tsconfig.json
的 module
字段修改为 esnext
,同时也修改 package.json
的 type
字段为 module
需要注意,nodemon
与 tsc
相关的命令也都有所改变,部分示例 package.json
如下,ncc
的用法保持不变
"scripts": {
"dev": "nodemon -x node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts",
"start:ts": "ts-node-esm --experimental-specifier-resolution=node src/app.ts",
"start:node": "node --es-module-specifier-resolution=node dist/app.js",
"build": "npx eslint . && npx ts-node-esm --experimental-specifier-resolution=node ./script/build.ts"
"build:tsc": "tsc --module esnext",
},
同时,所有 import
需要在原有基础上加入 .js
后缀(就比如,你要导入同目录下的 db.ts
,那么在他原来你应该写 import db from './db'
,但是在现在你需要写 import db from './db.js'
),而且编辑器一般不会自动补全和报错,dev 的时候也可以正常运行这一点我也很迷惑,但是给出的解释是让代码与打包后的更为相同(我:?????),也有解释是说因为编译器不会解析,所以需要手动添加,部分相关内容如下
https://github.com/microsoft/TypeScript/issues/16577
https://github.com/microsoft/TypeScript/issues/13422
https://github.com/microsoft/TypeScript/issues/33588
还有的地方的说法(如图)
当然,如果没有打包需求,可以不加,但是不加的话打包出来也不会加。本人没有使用 ncc 尝试,如果 ncc 打包后可以正常使用,那么本人更赞成原有的导入方法
参考文献
https://www.litf.com.cn/p/18
https://juejin.cn/post/7028417636811669534
https://dev.to/eiymba/compiling-typescript-to-esnext-for-back-end-node-js-apps-190l
https://www.typescriptlang.org/tsconfig#lib