TypeScript 模块

TS 使用和 JS 一样的 ES 模块系统(import/export),但额外提供了类型导入导出的能力——把"值"和"类型"区分开。这一章讲清楚 TS 模块的写法,重点是 import type 这个 TS 独有的语法。

1. 模块基础

在 TS 里,每个 .ts 文件默认就是一个模块,有自己的独立作用域。要用别的文件里的东西,必须先导出,再导入——和 JS 的 ESM 完全一样:

// user.ts —— 一个模块文件
// 每个 .ts 文件默认就是一个模块(有自己的作用域)

// 1. 命名导出:导出值
export const defaultName = "匿名";

export function greet(name: string): string {
  return `你好, ${name}`;
}

// 2. 导出类型(interface、type)
export interface User {
  id: number;
  name: string;
}

export type ID = number | string;

// 3. 默认导出:每个模块最多一个
export default class UserService {
  getUser(id: number): User {
    return { id, name: "默认用户" };
  }
}

2. 导入

导入也和 JS 一致:命名导入用花括号,默认导入不用花括号:

// app.ts —— 导入上面的模块
// 1. 导入命名导出
import { greet, defaultName } from "./user";

// 2. 导入默认导出(不用花括号,可以重命名)
import UserService from "./user";

// 3. 一次性导入所有
import * as UserModule from "./user";

// 4. 用起来
console.log(greet("小明"));
console.log(defaultName);
const svc = new UserService();

3. import type / export type(TS 独有)

这是 TS 相比 JS 最重要的模块增强。类型在运行时会被擦除,所以有时你需要明确告诉编译器:"这个东西是纯类型,不要打包到运行时代码里"。用 import type 就能做到:

// TS 特有:import type / export type
// 只导入/导出类型(运行时会被擦除),用于明确区分值和类型

import type { User, ID } from "./user";     // 只导入类型
import { greet } from "./user";             // 导入值

// 也可以在一个 import 里混用
import { greet, type User } from "./user";

// 导出端:export type
export type { User } from "./user";          // 只重导出类型

// 用 import type 的好处:
// 1. 让编译器/打包工具知道这是纯类型,可以安全擦除
// 2. 避免"类型出现在运行时"的循环依赖问题

实战中推荐养成习惯:只用作类型的导入,加 type 关键字。这样打包工具能更高效地擦除类型,也能避免一些循环依赖的诡异问题。

4. barrel 模式(汇总导出)

项目里常有这样的结构:一个目录下有很多模块,用一个 index.ts 统一汇总导出。这种模式叫 barrel(桶),让外部导入更简洁:

// barrel 模式:用一个 index.ts 汇总所有导出
// user.ts
export interface User { id: number; name: string; }

// post.ts
export interface Post { title: string; }

// index.ts(汇总)
export * from "./user";
export * from "./post";

// 外部使用时只需从 index 导入
import { User, Post } from "./models";    // 等价于从 index.ts 导入

这是大型项目组织代码的标准做法,几乎所有 TS 库(如 Vue、React)都用。

5. ES 模块 vs CommonJS

JS 历史上有两套模块系统:ESMimport/export,新标准)和 CommonJSrequire/module.exports,Node 老标准)。TS 默认用 ESM,但也能识别 CommonJS:

// TS 默认用 ES 模块(ESM),但也能识别 CommonJS
// CommonJS 是 Node 的老模块系统(require/module.exports)
const fs = require("fs");                   // CommonJS 风格
module.exports = { name: "hi" };

// 在 TS 里推荐统一用 ESM(import/export)
// tsconfig 里设置 "module": "ESNext" 或 "NodeNext"
// 这样配合打包工具(Vite/Webpack)或新版 Node 都最顺

新项目一律推荐 ESM。tsconfig 里把 module 设成 ESNextNodeNext,配合打包工具或新版 Node,体验最好。

6. 解析策略:classic vs node

TS 怎么根据 import "./user" 找到具体文件,由 moduleResolution 配置决定:

这部分会在 tsconfig 那一篇详讲。

小结

TS 模块 = JS 的 ESM + import type。核心要点:每个 .ts 文件是独立模块,用 import/export 互通,纯类型用 import type 区分。barrel 模式(index.ts 汇总)是大型项目的标准做法。下一篇讲 TS 日常开发最常用的工具类型(Partial/Record 等)。

← 上一篇 TypeScript 类

下一篇 TypeScript 工具类型

✈️💬