TypeScript CommonJS全局变量允许在没有编译器的ES模块构建中使用,

u2nhd7ah  于 6个月前  发布在  TypeScript
关注(0)|答案(5)|浏览(49)

🔎 搜索词

nodenext, module, __dirname

🕗 版本与回归信息

版本 5.4.5

⏯ Playground链接

  • 无响应*

💻 代码

package.json

"type": "module"

tsconfig.json

{
  "compilerOptions": {
    "module": "NodeNext"
  },
  "include": ["src"]
}

file.ts

console.log(__dirname)

🙁 实际行为

没有编译器错误,但这会导致Node中的运行时错误:

ReferenceError: __dirname is not defined in ES module scope

🙂 预期行为

编译器应发出类似于反向情况的错误。
例如,针对CommonJS:

package.json

"type": "commonjs"

file.ts

console.log(import.meta.dirname)

编译器会发出以下错误:

error TS1470: The 'import.meta' meta-property is not allowed in files which will build into CommonJS output.

关于问题的附加信息

也许我不明白的原因有一个很好的理由,但我认为 tsc 应该对会产生运行时错误的任何语法发出错误或警告。
这里有一个更完整的示例: https://github.com/knightedcodemonkey/tsc-module-globals

  • npm install
  • npm run esm(注意没有编译错误,但输出导致运行时错误)
  • npm run cjs(注意确实有编译错误)
pobjuy32

pobjuy321#

如果在目标为 "type": "module" 时,而使用 console.log(globalThis.__dirname) 仍然没有编译错误,并且节点不会抛出关于 __dirname 的 ReferenceError,因为它现在是 globalThis 的属性。然而,如果你执行 console.log(require.main),你仍然没有得到编译错误,并且节点会抛出一个关于 require 在 ES 模块范围内未定义的 ReferenceError。

在这里推荐的使用模式是什么?我知道编写 ES 模块的人经常会这样做:

const __dirname = dirname(fileURLToPath(import.meta.url))
zy1mlcev

zy1mlcev2#

这或多或少是可以预料到的,因为这些是由@types/node定义为全局的,没有办法说"声明全局,但只有在当前文件是CJS的情况下才生效"。

vd8tlhqk

vd8tlhqk3#

感谢反馈。
我想知道为什么编译器不会根据module设置和package.json文件中的type值,引入一些启发式方法来警告在使用CJS全局变量时针对ES模块输出?

x6492ojm

x6492ojm4#

TS没有“警告”的概念,尽管“建议”诊断很接近。这也是非平凡的,因为人们经常用一种关于转译的假设来编写ESM(但也许想要typeof require != "undefined"等),我们还认为任何名为require的函数在模块解析方面都应被视为require
如果你符合他们的指南,这里有一些可以严格对待这个问题的lint规则。

fhity93d

fhity93d5#

关于编译器行为的另一个有趣的事情是
给定:

cjs.ts

exports.foo = 'bar';

package.json

"type": "module"

file.ts

import './cjs.js'

module 的情况下,编译器不会将 exports.foo 转换为 export const foo。相反,你会得到

exports.foo = 'bar';
export {};

此外,没有编译器错误,只有运行时错误。
这是否与 #56678 有关?

相关问题