APE
文章标签归档关于

© 2026 APE.PUB

2026-10-25· 5 分钟

typescript-import-name

typescript

TS 项目 import 路径规则笔记

1. 裸模块说明符(bare specifier)vs 相对路径

import * as undici from "undici"; —— 为什么不用写具体文件路径 + 后缀?

  • 相对路径(./foo.js):Node ESM 解析器把它当字面文件路径处理,不做任何猜测,必须精确匹配磁盘上的文件。
  • 裸说明符("undici"):不以 ./、../、/ 开头,Node 走「包解析算法」:

1. 从当前文件所在目录开始,逐级向上找 node_modules/undici(monorepo 场景会一直找到根 node_modules);

2. 找到包目录后,读它的 package.json;

3. 按优先级看 exports 字段(现代包)或退化到 main 字段,决定这个裸名字映射到哪个真实文件。

例:undici 的 package.json 里 "main": "index.js",所以 "undici" 实际被解析成 node_modules/undici/index.js。

import * as undici from "undici" 这种 namespace import 会把该包所有具名导出打包成一个对象,适合既要用值(类、函数)又要用类型(如 undici.Dispatcher)的场景,可以用同一个标识符访问,少写几条 import。

2. 路径别名(@/...)为什么能省略后缀

import { convertDateStr } from '@/common/utils/date-utils-v2.util'(常见于 NestJS 等用 CommonJS/ts-node/webpack 的项目):

1. @/ 是路径别名,不是真实路径:在 tsconfig.json 的 paths 里配置过,如 "@/": ["src/"]。这不是 Node 原生语法,必须靠额外工具(TS 编译器、tsconfig-paths、webpack/jest 的 moduleNameMapper、SWC 等)在编译期或运行期翻译成真实路径。

2. 解析走的是传统 CommonJS 风格的扩展名探测:moduleResolution 是 "node"(经典模式)或 "bundler",遇到不带后缀的路径时会依次尝试 .ts、.tsx、.js、/index.ts 等,直到找到存在的文件。

这跟 Node 原生 ESM(见第 3 节)是完全不同的两套规则,不能混用经验。

3. pi 项目:相对导入为什么必须写 .js,又能写 .ts

pi 项目 package.json 里 "type": "module",走 Node 原生 ESM 解析(moduleResolution: "NodeNext"),相对路径必须精确匹配,不会自动补后缀——所以常规写法下相对导入必须显式写 .js。

但在这个仓库的 tsconfig.base.json 里又开了两个选项,使得可以直接写 .ts:

"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true
  • allowImportingTsExtensions:允许在 import 说明符里写 .ts 后缀,TS 编译器不再报错。
  • rewriteRelativeImportExtensions(TS 5.7+):编译产物(dist/ 下的 .js)里会把 .ts 自动重写成 .js。

效果:

  • 源码写法:import type { SessionManager } from "./session-manager.ts";
  • 编译产物:import type { SessionManager } from "./session-manager.js";

即开发时「所见即所得」写真实文件后缀(编辑器跳转、类型检查都对应真实的 .ts 文件),编译后产物仍符合 Node ESM 严格要求的 .js 后缀规则。

另外 import type 本身是纯类型导入,运行时会被完全擦除,不会生成任何 JS 代码。

小结对照表

| 写法 | 场景 | 解析机制 |

|---|---|---|

| import x from "pkg" | npm 包裸名 | Node 包解析算法,查 node_modules + package.json 的 exports/main |

| import x from "@/foo/bar.util" | 路径别名 + 省略后缀 | tsconfig paths 映射 + CommonJS 风格扩展名探测(node/bundler 解析) |

| import x from "./foo.js" | Node 原生 ESM 相对导入 | 字面路径匹配,必须写真实产物后缀 .js |

| import x from "./foo.ts" | 本仓库(allowImportingTsExtensions + rewriteRelativeImportExtensions) | 源码写 .ts,编译时自动重写为 .js |

← 返回首页