在TypeScript中,导入或导出为“顶级”是什么意思?

时间:2019-02-16 13:35:57

标签: typescript

TypeScript docs说:

  

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

导入或导出为“顶级”是什么意思?

2 个答案:

答案 0 :(得分:2)

  

打字稿的顶层是最外面的范围。

什么是“范围”?

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

例如:

import { something } from "<module>"; <-- Global / Top-level scope

function divide(x, y) { <-- Start function scope
  if(y == 0) { <-- Start of the if's scope
    /* 
     * Here is a child scope of the function
     * This means x and y are available here.
     */

    var error = new Error("Cannot divide by 0); <-- "error" is only available here.
    throw error;
  } <-- End of the if's scope

  /* 
   * The "error" variable is not available here
   * since the scope it was defined in, was already closed.
   */

  return x / y;
} <-- Ends the functions scope

var z = 0; <-- Global scope

这意味着:

import { x } from "<module>"
/* rest of code */

可以,但是例如:

if (true) {
  import { x } from "<module>";
}

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

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

function add(a, b) {
  return a + b;
}

import { x } from "<module>";

这仍然有效,因为函数的范围以右括号}结尾。意味着之后的所有内容都再次位于顶层。

关于import的所有说法也适用于export


1:有时您可以省略{|}大括号以创建新的作用域。您仍然可以创建一个新的作用域,但是要隐式地进行。 例如,考虑下面的两个片段-它们是相同的。语言以词法创建作用域-作用域不是由标记定义的

if(true)
  return true;
else
  return false;

相同
if(true) {
  return true;
} else {
  return false;
}

答案 1 :(得分:1)

顶级import是静态导入,位于文件的最顶部。但是,它之所以称为“顶级”,不是因为它位于文件的顶部,而是因为存在不是顶级的动态导入:

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(/* ... */) 

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

如果您放置两个没有顶级导入/导出的文件,并且两个标识符相同,则会出现错误:

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

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

之所以发生这种情况,是因为没有顶级导出/导入声明,并且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.