使用Babel转译Node.js+TypeScript项目为何未保留可选链语法?
我明白你的困惑——明明Node.js 14+已经原生支持可选链和空值合并运算符,但Babel还是把它们转成了兼容旧版本的代码,这确实有点反直觉。问题出在你的@babel/preset-env配置上,具体来说是没有明确指定目标运行环境。
原因分析
默认情况下,@babel/preset-env会以> 0.25%, not dead作为目标环境(也就是兼容绝大多数仍在使用的浏览器和Node.js版本),所以即使你本地用的是Node.js 14,它还是会转译这些特性来适配更旧的环境。shippedProposals: true只是让Babel支持那些已经被主流环境(包括Node.js)正式纳入的提案语法,但它不会改变预设的目标环境规则——只要目标环境里有不支持该特性的版本,Babel就会转译。
另外你提到移除@babel/preset-typescript后结果还是一样,这很正常:转译这两个运算符的逻辑是由@babel/preset-env(或其依赖的@babel/plugin-proposal-optional-chaining、@babel/plugin-proposal-nullish-coalescing-operator插件)处理的,和TypeScript预设无关。
解决方案
你需要在@babel/preset-env的配置里明确指定你的目标Node.js版本,这样Babel就会跳过对已支持特性的转译。有两种方式可以实现:
指定具体的Node.js版本
修改你的.babelrc里的@babel/preset-env配置,添加targets.node字段:{ "presets": [ "@babel/preset-typescript", [ "@babel/preset-env", { "shippedProposals": true, "targets": { "node": "14.15.3" // 填写你需要支持的最低Node版本 } } ] ], "plugins": [ [ "module-resolver", { "root": "./src", "alias": { "@root": ["./"], "@src": ["./src"] }, "extensions": [".js", ".ts"] } ] ], "sourceMaps": true }自动匹配当前Node版本
如果你希望Babel自动适配你当前正在使用的Node.js版本,可以用"node": "current":{ "presets": [ "@babel/preset-typescript", [ "@babel/preset-env", { "shippedProposals": true, "targets": { "node": "current" } } ] ], "plugins": [ [ "module-resolver", { "root": "./src", "alias": { "@root": ["./"], "@src": ["./src"] }, "extensions": [".js", ".ts"] } ] ], "sourceMaps": true }
验证修改
调整配置后,重新运行你的构建命令:
rm -rf build/ && babel src --source-maps --extensions '.js,.ts,.tsx' --ignore '**/*.test.ts' -d build
这时候console.log(x?.ciao ?? 10)应该会保留原生语法,不再被转译。
内容的提问来源于stack exchange,提问作者devamat




