在TypeScript中,导入或导出为"顶级"意味着什么?

Dan*_* B. 6 typescript

打字稿文档说:

在TypeScript中,就像在ECMAScript 2015中一样,任何包含顶级文件import或被export视为模块的文件.相反,没有任何顶级importexport声明的文件被视为脚本,其内容在全局范围内可用(因此也可用于模块).

进口或出口是"顶级"是什么意思?

Nur*_*yev 8

顶层import静态导入,位于文件的最顶部。强调static,它被称为“顶级”不是因为它位于文件的顶部,而是因为存在非顶级的动态导入:

import foo from 'foo' // top level import, static one

import('foo').then(/* ... */) // not top level import, dynamic one

// no static top-level import can live here (after any code that is not a top-level import declaration)

function bar() {
  import('foo').then(/* ... */) // not top level import, dynamic one
  // no static top-level import can live here
  // no export can live here too
}

// no static top-level import can live here

export const baz = 123 // exports are always top level, and static

// You still can add not top level imports here, in the very end
import('foo').then(/* ... */) 
Run Code Online (Sandbox Code Playgroud)

现在,为什么这在 Typescript 中很重要?

如果您放置两个没有顶级导入/导出的文件,并且它们具有两个相同的标识符,您将收到错误:

// a.ts
let foo = 1 // Error: duplicate identifier

// b.ts
let foo = 1 // Error: duplicate identifier
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为没有顶级导出/导入声明,并且 TS 认为这些文件是scripts(与 相比modules)。如果在浏览器中加载两个具有相同标识符的脚本会发生什么?是的,会出现“重复标识符”错误。因为这两个变量都位于全局命名空间中。

因此,为了避免这种情况,您可以这样做:

// a.ts
let foo = 1 // Ok

// b.ts
let foo = 1 // Ok
export {} // This is the magic. b.ts is now a module and hence, is not polluting the global namespace.
Run Code Online (Sandbox Code Playgroud)


Pat*_*eck 4

\n

Typescript 中的顶层是最外层的范围。

\n
\n\n

什么是“范围”?

\n\n

每次打开一组大{括号\xc2\xb9 时都会创建一个作用域。\n作用域将变量和函数的可见性限制在它们定义的作用域和子作用域内。

\n\n

例如:

\n\n
import { something } from "<module>"; <-- Global / Top-level scope\n\nfunction divide(x, y) { <-- Start function scope\n  if(y == 0) { <-- Start of the if\'s scope\n    /* \n     * Here is a child scope of the function\n     * This means x and y are available here.\n     */\n\n    var error = new Error("Cannot divide by 0); <-- "error" is only available here.\n    throw error;\n  } <-- End of the if\'s scope\n\n  /* \n   * The "error" variable is not available here\n   * since the scope it was defined in, was already closed.\n   */\n\n  return x / y;\n} <-- Ends the functions scope\n\nvar z = 0; <-- Global scope\n
Run Code Online (Sandbox Code Playgroud)\n\n

这意味着:

\n\n
import { x } from "<module>"\n/* rest of code */\n
Run Code Online (Sandbox Code Playgroud)\n\n

有效,但例如:

\n\n
if (true) {\n  import { x } from "<module>";\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

不起作用,因为导入包含在 if 语句的范围内,因此不再位于顶级范围。

\n\n

但这并不意味着“顶级”位于文件的顶部。它仅意味着最外层的范围。

\n\n
function add(a, b) {\n  return a + b;\n}\n\nimport { x } from "<module>";\n
Run Code Online (Sandbox Code Playgroud)\n\n

这仍然有效,因为函数的范围以右大}括号 \xc2\xb9 结束。意味着一切都再次回到顶层。

\n\n

关于import\'s 的所有内容也适用于export\'s

\n\n
\n\n

\n1:有时您可以省略{|}大括号来创建新范围。您仍然创建一个新作用域,但隐式执行此操作。\n例如,请考虑下面的两个片段 - 它们是相同的。语言按词法创建作用域 - 作用域不是由标记定义的\n

\n\n
if(true)\n  return true;\nelse\n  return false;\n
Run Code Online (Sandbox Code Playgroud)\n\n

是相同的

\n\n
if(true) {\n  return true;\n} else {\n  return false;\n}\n
Run Code Online (Sandbox Code Playgroud)\n