编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

    • README
    • HTML工具手册

    • CSS样式与布局

    • JavaScript核心

    • TypeScript入门

      • README
      • TS类型系统基础
      • TS接口与对象类型
      • TS函数与类实战
      • TS泛型编程实战
      • TS高级类型编程
      • TS类型守卫机制
      • TS模块系统详解
        • 1. 案例引入
          • 1.1 一个模块化的灾难
          • 1.2 好的模块化
        • 2. ES Module 导出与导入
          • 2.1 导出的四种方式
          • 2.2 导入的六种语法
        • 3. import type / export type
          • 3.1 为什么需要"只导入类型"
          • 3.2 混合导入
        • 4. 模块解析策略
          • 4.1 两种策略:node 与 classic
          • 4.2 路径别名配置
          • 4.3 路径别名与构建工具的联动
        • 5. namespace 命名空间
          • 5.1 namespace 基础
          • 5.2 namespace 与 ES Module 的选择
        • 6. declare 全局声明
          • 6.1 declare 的三类使用
          • 6.2 模块扩充(Module Augmentation)
          • 6.3 全局类型扩充
        • 7. 三斜线指令
        • 8. 模块化的最佳实践
          • 8.1 导出设计原则
          • 8.2 循环依赖解决方案
        • 9. 速查表
      • TS工程配置实践实践
    • Vue高级进阶

    • Web工程化实践

  • Linux应用开发

  • IoT智能硬件开发

  • Apps
  • Web开发和进阶
  • TypeScript入门
杨充
2025-06-24
目录

TS模块系统详解

# 07.TS模块系统详解

ES Module 如何在 TS 中实现类型安全?import type、声明文件、模块增强——构建可扩展的模块化代码。

# 1. 案例引入

# 1.1 一个模块化的灾难

// user.ts —— 导出了太多东西
export class User {}
export function createUser() {}
export function updateUser() {}
export function deleteUser() {}
export const API_URL = "/api/users";
// ... 20 行后还在 export

// 另一文件
import { User, createUser } from "./user";  // 从哪里找?找不到定义在哪个文件

// 循环依赖——A 引用 B,B 引用 A
// import { something } from "./circle-b";
// 编译时可能不报错,运行时可能 undefined

# 1.2 好的模块化

// user/models.ts —— 只用 export type 暴露类型
export interface User { id: number; name: string; }

// user/api.ts —— 清晰的导出
import type { User } from "./models";  // 只导入类型,编译后完全消失
export async function getUser(id: number): Promise<User> { /* ... */ }

// 消费者
import { getUser } from "./user/api";
const user = await getUser(1);  // user: User —— 类型自动传递

# 2. ES Module 导出与导入

# 2.1 导出的四种方式

// 1. 声明时导出
export const API_URL = "https://api.example.com";
export function fetchData() {}
export interface User { id: number; }

// 2. 默认导出(一个模块只能一个)
export default class App {}

// 3. 统一导出
const a = 1, b = 2;
export { a, b };

// 4. 重命名导出
export { a as valueA, b as valueB };
export { default as AppComponent } from "./App";

# 2.2 导入的六种语法

// 1. 命名导入
import { fetchData, API_URL } from "./api";

// 2. 默认导入
import App from "./App";

// 3. 混合导入
import App, { fetchData } from "./api";

// 4. 全部导入为命名空间
import * as Api from "./api";
Api.fetchData();
Api.API_URL;

// 5. 仅执行模块副作用(不导入任何绑定)
import "./init.css";

// 6. 重命名导入
import { fetchData as getData } from "./api";

# 3. import type / export type

# 3.1 为什么需要"只导入类型"

// 普通 import——编译后可能在 JS 中保留引用
import { User } from "./models";  // 编译后:var models_1 = require("./models");

// import type——编译后完全消失
import type { User } from "./models";  // 编译后:无任何代码

// 好处 1:避免循环依赖(类型不产生运行时引用)
// 好处 2:减小打包体积
// 好处 3:明确意图——"我只用类型"

# 3.2 混合导入

// 同时导入值和类型
import { createUser, type User } from "./user";

// export type——只导出类型
export type { User, Config } from "./types";

# 4. 模块解析策略

# 4.1 两种策略:node 与 classic

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node"  // 或 "classic" / "bundler"(TS 5.0+)
  }
}
node 策略(推荐):
  import { foo } from "./utils"
  → 找 ./utils.ts → ./utils/index.ts → package.json types
  ↓ 模仿 Node.js 的 require 解析

bundler 策略(TS 5.0+,配合 Vite/Webpack):
  不需要写完整扩展名,支持 package.json exports

# 4.2 路径别名配置

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@/*": ["./*"],
      "@components/*": ["./components/*"],
      "@utils/*": ["./utils/*"],
      "@types/*": ["./types/*"]
    }
  }
}
// 优雅的导入
import { Button } from "@components/Button";
import { formatDate } from "@utils/date";
import type { User } from "@types/user";

# 4.3 路径别名与构建工具的联动

TS 只负责类型检查——不负责打包
必须让构建工具(Webpack/Vite)也识别路径别名

Vite (vite.config.ts):
  resolve: { alias: { "@": "/src" } }

Webpack (webpack.config.js):
  resolve: { alias: { "@": path.resolve(__dirname, "src") } }

# 5. namespace 命名空间

# 5.1 namespace 基础

// 命名空间——将相关代码组织在一个名字下
namespace Geometry {
    export interface Point { x: number; y: number; }

    export function distance(a: Point, b: Point): number {
        return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
    }
}

const p1: Geometry.Point = { x: 0, y: 0 };
const d = Geometry.distance(p1, { x: 3, y: 4 });

# 5.2 namespace 与 ES Module 的选择

namespace —— 旧时代遗留(AMD/全局脚本时代)
  优点:可以跨文件合并声明
  缺点:现代构建工具不友好

ES Module —— 现代标准
  优点:原生支持、树摇(Tree Shaking)、异步加载
  缺点:不能同名合并

选型结论:
  新项目 → ES Module(永远)
  旧项目 → namespace → 逐步迁移为 ES Module

# 6. declare 全局声明

# 6.1 declare 的三类使用

// 1. 声明全局变量(给以 <script> 引入的库补类型)
declare var jQuery: (selector: string) => any;

// 2. 声明全局函数
declare function greet(name: string): void;

// 3. 声明全局模块
declare module "*.css" {
    const content: Record<string, string>;
    export default content;
}

# 6.2 模块扩充(Module Augmentation)

// 原始定义(node_modules 的第三方库)
// export interface AxiosInstance { get<T>(url: string): Promise<T>; }

// 你的项目——扩展 Axios 实例
import axios from "axios";

declare module "axios" {
    interface AxiosInstance {
        getUser<T>(): Promise<T>;
        postForm<T>(data: FormData): Promise<T>;
    }
}

// 现在可以使用扩展方法(类型安全)
const user = await axios.getUser<User>();

# 6.3 全局类型扩充

// 为 Window 对象添加自定义属性
declare global {
    interface Window {
        __APP_CONFIG__: {
            apiUrl: string;
            version: string;
        };
    }
}

// 使用
const apiUrl = window.__APP_CONFIG__.apiUrl;  // string

# 7. 三斜线指令

// 引入类型声明文件(现代项目中极少使用——被 tsconfig types 替代)
/// <reference path="./other.d.ts" />

/// <reference types="node" />     // 引入 @types/node
/// <reference lib="dom" />        // 引入标准库

# 8. 模块化的最佳实践

# 8.1 导出设计原则

// ❌ 过度导出
// 每个函数、每个类型都 export —— 边界模糊

// ✅ 分层导出策略

// 1. 内部实现(不导出)
const INTERNAL_CONST = 42;

// 2. 公共 API(选择性导出)
export function getUser(id: number): Promise<User> { /* ... */ }

// 3. 类型入口(用 barrel export)
// index.ts
export type { User, Config } from "./types";
export { getUser, createUser } from "./user";
export { formatDate, formatCurrency } from "./utils";

# 8.2 循环依赖解决方案

// 问题:A 导入 B,B 导入 A
// ├── parent.ts: import { Child } from "./child"
// └── child.ts:  import { Parent } from "./parent"

// 解决方案 1:提取共享类型到单独文件
// types.ts:  export interface Parent { ... }  export interface Child { ... }

// 解决方案 2:使用 import type(最推荐)
// child.ts:
import type { Parent } from "./parent";  // 类型导入不会产生循环依赖

# 9. 速查表

语法 作用 示例
export const 导出值 export const API = "..."
export default 默认导出 export default class
import type 仅导入类型(编译后消失) import type { User }
export type 仅导出类型 export type { Config }
import * as 命名空间导入 import * as API
paths tsconfig 路径别名 "@/*": ["./src/*"]
namespace 旧式命名空间 namespace X { export ... }
declare var 声明全局变量类型 declare var jQuery
declare module 扩充模块类型 declare module "*.css"
declare global 扩充全局类型 declare global { interface Window }

下一篇:08.TS工程配置实践

上次更新: 2026/06/24, 12:59:24
TS类型守卫机制
TS工程配置实践实践

← TS类型守卫机制 TS工程配置实践实践→

最近更新
01
CSS选择器入门
06-23
02
CSS定位与层级
06-23
03
CSS盒模型详解
06-23
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式