第 1 节 概述
前九篇的所有代码示例都在单个文件里。但真实项目——几百个文件、几千行代码——怎么组织才能不混乱?
答案是模块。每个文件是一个模块,模块之间通过 import / export 建立依赖关系。
TypeScript 沿用了 JavaScript 的 ES Module 标准,并在此基础上增加了类型导出相关的特性。
第 2 节 模块基础
一个文件就是一个模块,模块通过 export 暴露内容,通过 import 引入内容。
导出(export):
1
2
3
4
5
6
7
8
9
10
11
| // math.ts
export function add(a: number, b: number): number {
return a + b
}
export const PI = 3.14159
export interface Point {
x: number
y: number
}
|
导入(import):
1
2
3
4
5
| // app.ts
import { add, PI, type Point } from "./math"
const p: Point = { x: 10, y: 20 }
console.log(add(PI, 0.00001))
|
2.1 默认导出
每个模块可以有零个或一个默认导出:
1
2
3
4
5
6
7
8
9
| // config.ts
export default {
apiUrl: "https://api.example.com",
timeout: 5000,
}
// 导入时,名字可以任意取
import config from "./config"
// import myConfig from "./config" 也可以
|
技巧
团队项目中约定导出的风格更好。一些团队只用命名导出(export),因为默认导出的重命名给代码阅读造成负担。另一些团队在"一个文件一个主要功能"时用默认导出。保持一致即可。
2.2 重导出
可以集中导出一个目录下多个模块的内容:
1
2
3
4
| // index.ts —— 目录的入口文件
export { User, createUser } from "./user"
export { Post, createPost } from "./post"
export type { ApiResponse } from "./types"
|
第 3 节 类型导入
当只导入类型时,可以加 type 关键字,编译时会被移除:
1
2
3
4
5
6
7
8
| // 只导入值(编译后保留)
import { formatDate } from "./utils"
// 只导入类型(编译后消失)
import type { User, Post } from "./types"
// 混合同一个源文件
import { createUser, type User } from "./user"
|
说明
import type 是 TypeScript 3.8 引入的特性。它明确告诉编译器"我只需要类型声明",在某些构建工具中可以触发更优化的编译策略。TypeScript 5.0 后,如果你显式写了 type,编译器会建议你使用 import type 语法。
同样地,导出时也可以标记类型:
1
2
3
| export type { User }
// 或者
export { type User, createUser }
|
第 4 节 模块解析
当我们写 import { add } from "./math" 时,TypeScript 怎么找到这个文件?
相对路径导入(以 ./ 或 ../ 开头):解析为相对于当前文件的位置。
1
2
| import { User } from "./types/user" // 当前目录的 types/user.ts
import { Config } from "../config" // 上级目录的 config.ts
|
非相对路径导入(不以 ./ 或 ../ 开头):在 node_modules 中查找。
1
2
| import { ref } from "vue" // node_modules/vue
import { defineConfig } from "vite" // node_modules/vite
|
TypeScript 编译器自动解析文件扩展名(.ts、.tsx、.d.ts)和 index.ts:
1
2
3
4
5
6
7
8
| // 以下导入方式都有效
import { User } from "./models/user"
// 会按顺序查找:
// ./models/user.ts
// ./models/user.tsx
// ./models/user.d.ts
// ./models/user/index.ts
// ./models/user/index.d.ts
|
第 5 节 路径别名
在 tsconfig.json 中配置路径别名,避免深层相对路径:
配置后,可以用简洁的路径导入:
1
2
3
| // 不用 ../../../types/user
import { User } from "@/types/user"
import { formatDate } from "@utils/date"
|
第 6 节 namespace 简述
namespace 是 TypeScript 早期的模块方案(在 ES Module 标准化之前使用)。现在很少用了,但了解旧项目时需要:
1
2
3
4
5
6
7
8
9
10
11
| namespace Geometry {
export const PI = 3.14159
export function areaOfCircle(radius: number): number {
return PI * radius * radius
}
}
// 使用
console.log(Geometry.PI)
console.log(Geometry.areaOfCircle(5))
|
namespace 也可以跨文件,通过 /// <reference> 引用。
注意
现代 TypeScript 项目应使用 ES Module(import/export),而不是 namespace。只有在你写全局声明文件(.d.ts)时,namespace 还有一席之地。
第 7 节 文件组织建议
中型 TypeScript 项目的常见目录结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
| src/
├── types/ # 类型定义
│ ├── user.ts
│ ├── api.ts
│ └── index.ts # 重导出所有类型
├── utils/ # 工具函数
│ ├── date.ts
│ └── format.ts
├── services/ # API 调用
│ └── userService.ts
├── models/ # 数据模型
│ └── User.ts
└── index.ts # 应用入口
|
几个组织原则:
| 原则 | 说明 |
|---|
| 按功能分目录 | 类型放 types/,工具放 utils/,服务放 services/ |
| 每个文件一个主要概念 | user.ts 只导出 User 相关的类型和函数 |
目录入口 index.ts | 集中导出目录内容,外部只引目录路径 |
| 类型和逻辑分开 | 纯类型定义放 types/,运行时逻辑不放类型文件 |
模块化让你能把千行代码组织得井井有条。
现在你有了完整 TypeScript 技能树:基础类型 → 类型运算 → 对象/接口/类 → 泛型 → 守卫 → 模块。
下一篇是真正的"进阶"篇——类型工具、映射类型、条件类型、声明文件……这些是 TypeScript 高手的武器库。