模块
在 TypeScript 中,是一种组织和封装代码的方式,它帮助开发者管理大型项目中的代码结构,支持代码的复用和隔离命名空间,以避免全局变量污染。TypeScript 模块系统主要通过 import 和 export 语句来实现模块之间的交互。下面是一些关键概念和使用方法:
基本概念
- 文件即模块:在 TypeScript 中,每个 .ts 文件都被视为一个独立的模块,除非显式地使用 namespace(命名空间)来定义模块。
- 导出(export):使用 export 关键字可以让模块中的成员(如函数、类、接口、变量等)对外部可见,可供其他模块导入和使用。
- 导入(import):使用 import 关键字可以从其他模块中导入所需的成员。你可以导入整个模块,或者只导入特定的成员。
导出方式
- 默认导出(default export):每个模块只能有一个默认导出。使用 来定义,默认导出的成员可以被导入时任意命名。
ts
// moduleA.ts
export default function sayHello(name: string) {
console.log(`Hello, ${name}!`);
}
// 使用默认导入
import sayHello from "./moduleA";
sayHello("World");- 命名导出(named exports):一个模块可以有多个命名导出,使用 前缀声明。
ts
// moduleB.ts
export function add(a: number, b: number): number {
return a + b;
}
export interface Person {
name: string;
age: number;
}
// 命名导入
import { add, Person } from "./moduleB";模块导入路径
- 相对路径:以.或..开头,根据当前文件位置找到模块。
- 绝对路径:从项目根目录开始的路径,通常用于配置第三方模块的导入。
命名空间(Namespace)与模块
尽管命名空间也是组织和封装代码的一种方式,但它更偏向于传统的面向对象编程。在现代 TypeScript 开发中,推荐使用模块系统(基于文件和 import/export)而不是命名空间,因为模块系统更符合 ES6 及以后的 JavaScript 标准,且能更好地支持模块打包工具和现代开发流程。
declare module 和 declare namespace
主要用于定义第三方库或全局模块的类型声明,特别是当你不能直接修改或访问到库的源代码时。它允许你为现有的 JavaScript 模块或全局变量提供类型信息,使得 TypeScript 编译器能够识别并进行类型检查。ts
// 假设有个第三方库foo没有类型声明文件
declare module "foo" {
export function doSomething(): void;
export const someConstant: number;
}在这个例子中,我们为名为 foo 的模块提供了一个类型声明,告诉 TypeScript 它有一个名为 doSomething 的函数和一个名为 someConstant 的常量。
则用于定义一个命名空间,它是组织和封装一系列相关类型(如类、接口、函数等)的方式,以避免全局命名冲突。命名空间可以嵌套,形成层次化的类型结构。ts
declare namespace MyLibrary {
export interface User {
id: number;
name: string;
}
export function getUser(id: number): User;
}上面的例子中,MyLibrary 命名空间包含了 User 接口和 getUser 函数的声明,它们都是这个命名空间的一部分。
- 目的:declare module 更侧重于为外部模块提供类型定义,尤其是那些没有直接提供 TypeScript 类型信息的库。而 declare namespace 则侧重于组织和提供自己代码的类型声明,构建层次清晰的类型体系。
- 使用场景:当你需要为第三方库添加类型定义时,使用 declare module。当你在构建自己的库或项目,需要组织类型以避免命名冲突时,使用 declare namespace。
- 模块系统:declare module 通常与 CommonJS 或 UMD 等模块系统关联更紧密,而 namespace 则更偏向于在代码中创建逻辑上的分组,尽管它也可以在模块系统中使用。
- 兼容性:namespace 在 TypeScript 早期版本中较为常见,随着 ES 模块(使用 import/export)的普及,直接使用模块系统来组织代码变得更为推荐,但 namespace 仍然有其应用场景,尤其是在需要模拟全局命名空间或组织大型项目类型定义时。
总结
TypeScript 的模块系统极大地增强了代码的组织性和可维护性,通过清晰的导入导出机制,促进了代码的复用和解耦。掌握模块的使用对于构建大规模的、结构化的 TypeScript 应用程序至关重要。