TypeScript 模块解析

TypeScript 模块解析

模块解析就是指编译器所要依据的一个流程,用它来找出某个导入操作所引用的具体值。

假设有一个导入语句import { a } from "moduleA"; 为了去检查任何对a的使用,编译器需要准确的知道它表示什么,并且会需要检查它的定义moduleA。这时候,编译器会想知道:moduleA的shape是怎样的?这听上去很简单,moduleA可能在你写的某个.ts/.tsx文件里或者在你的代码所依赖的.d.ts里。

首先,编译器会尝试定位表示导入模块的文件。编译器会遵循下列二种策略之一:Classic或Node。这些策略会告诉编译器到哪里去查找moduleA。如果它们失败了并且如果模块名是非相对的(且是在"moduleA"的情况下),编译器会尝试定位一个外部模块声明。我们接下来会讲到非相对导入。最后,如果编译器还是不能解析这个模块,它会记录一个错误。在这种情况下,错误可能为error TS2307: Cannot find module 'moduleA'.

相对 vs. 非相对模块导入

根据模块引用是相对的还是非相对的,模块导入会以不同的方式解析。

相对导入是以/./../开头的。下面是一些例子:

import Entry from "./components/Entry";
import { DefaultHeaders } from "../constants/http";
import "/mod";

所有其它形式的导入被当作非相对的,下面是一些例子:

import * as $ from "jQuery";
import { Component } from "@angular/core";

相对导入解析时是相对于导入它的文件来的,并且不能解析为一个外部模块声明。你应该为你自己写的模块使用相对导入,这样能确保它们在运行时的相对位置。

非相对模块的导入可以相对于baseUrl或通过下文会讲到的路径映射来进行解析。它们还可以被解析能外部模块声明。使用非相对路径来导入你的外部依赖。

模块解析策略

共有两种可用的模块解析策略:Node和Classic。你可以使用--moduleResolution标记指定使用哪种模块解析策略。若未指定,那么在使用了--module AMD | System | ES2015时的默认值为Classic,其它情况时则为Node。

TypeScript如何解析模块

TypeScript是模仿Node.js运行时的解析策略来在编译阶段定位模块定义文件。因此,TypeScript在Node解析逻辑基础上增加了TypeScript源文件的扩展名(.ts,.tsx和.d.ts)。同时,TypeScript在package.json里使用字段"types"来表示类似"main"的意义 - 编译器会使用它来找到要使用的”main”定义文件。

比如,有一个导入语句import { b } from "./moduleB"在/root/src/moduleA.ts里,会以下面的流程来定位"./moduleB":

/root/src/moduleB.ts
/root/src/moduleB.tsx
/root/src/moduleB.d.ts
/root/src/moduleB/package.json (如果指定了"types"属性)
/root/src/moduleB/index.ts
/root/src/moduleB/index.tsx
/root/src/moduleB/index.d.ts