# 模块解析

在 TypeScript 中使用 import a from 'ModuleA' 或 import a from './ModuleA' 语法时,TypeScript 如何确定 ModuleA 的实际位置?编译器分析导入内容位置的过程就是本章讨论的模块解析 。

# 模块解析概述

TypeScript 存在两种典型的 模块解析 策略。

  • Classic
  • Node

# 关联导入和非关联导入

  • 关联导入(relative import) 以 /,./,../. 开头的导入,本地文件的导入
  • 非关联导入(non-relative import) 模块名的方式导入,引用三方的模块导入,例如 import * as $ from "jquery",import { Component } from "@angular/core"; ,非关联导入具有如下特性
    • 可以通过 baseUrl 配置改变 模块解析 规则
    • 会解析 ambient module declarations

# 模块解析策略

  • moduleResolution 配置可以修改解析策略
  • 未显示指定模块解析策略时根据配置的 module 类型处理解析规则
    • commonjs 采用 node 解析
    • amd, system, umd, es2015, esnext 采用 classic 模式解析

TIP

在开发 npm 包时,若定义模块为 es2015, esnext 的 esm 导出方式,则建议配置 moduleResolution 为 node, 采用类似 node 的方式处理模块解析

# Classic 策略

  1. 关联导入
    1. 先解析路径下的 .ts 为后缀的文件
    2. 若无则查找 .d.ts 文件
  2. 非关联导入
    1. 在当前目录查找 .ts 为后缀的模块名文件
    2. 若无,则在当前目录查找 .d.ts 结尾的模块名文件
    3. 若无则,则在上一级目录重复步骤 1,2
    4. 若无则重复步骤 3

若最后模块解析失败,ts 会抛出 error TS2307: Cannot find module xxx. 的信息

# Node 策略

加载机制详见 node 模块加载机制 (opens new window)

重点如下:

  • 相对路径
    • node 会先加载不带任何后缀的文件作为 js 文件解析,随后按照 js,json,node 的后缀加载文件
    • 若文件无法查找到,按照同名文件夹会读取 package.json main 字段,不存在会查找 index 文件按照 js,json,node 扩展顺序进行加载

      注意此处不会加载没有扩展名文件,若文件夹下 index 无扩展名会直接抛出错误

  • 绝对路径
    • 对于不包含路径的模块,会先去加载内部模块若失败,会根据module.paths 的一系列目录加载,回逐级向上查找 node_modules 目录寻找模块

      可以通过 NODE_PATH 来增加解析路径。利用 : 分隔多个目录。windows 为 ;

TypeScript 的规则类似

  1. 相对路径查找 ./moduleB
    1. 在当前路径查找名为 moduleB.ts,moduleB.tsx,moduleB.d.ts 的文件
    2. 在当前路径的 package.json 查找 types 字段对应的文件位置
    3. 在当前路径 moduleB 文件夹下查找 index.ts,index.tsx,index.d.ts 文件
    4. 若未找到退化到 node 的查找机制
  2. 绝对路径,查找 moduleB
    1. 在 node_modules 目录查找后缀为 moduleB.ts,moduleB.tsx,moduleB.d.ts 文件
    2. 在 node_modules/moduleB/package.json types 字段查找 .ts,.tsx,.d.ts 文件
    3. 在 node_modules/moduleB 字段查找 index.ts,index.tsx,index.d.ts 文件
    4. 在 node_modules/@types/moduleB.d.ts 字段查找 index.ts,index.tsx,index.d.ts 文件
    5. 在 node_modules/@types/moduleB 字段查找 index.ts,index.tsx,index.d.ts 文件
    6. 重复 1-5 向上一层查找 node_modules 目录

# 模块解析配置

除了上述默认查找规则,可以利用如下配置定义解析器查找机制。

  • baseUrl 所有非相对路径模块导入会参考此地址导入。
  • paths 有时模块的位置上述查找无法生效,例如 jquery 的编译文件定义在 node_modules/jquery/dist/jquery 为了避免查找失败,通过此路径匹配

    注意 paths 的值是相对于 baseUrl 而言的,所以需要设置 baseUrl 为 . 避免查找失败 也可利用此示例实现跨模块查找

  • rootDirs 实现编译时的动态载入,详见 rootDirs (opens new window)

# export type

详见 export type (opens new window)

# 知识点

  1. 解决什么问题
  2. 核心概念有哪些
    1. 导入定义
      1. 关联导入(relative import) 以 /,./,../. 开头的导入
      2. 非关联导入(non-relative import)
  3. 如何影响该特性
  4. 实际使用场景