TypeScript - 模块
TypeScript - 模块 (ES 模块)
Section titled “TypeScript - 模块 (ES 模块)”模块(Modules)是现代 JavaScript 和 TypeScript 中用于将代码组织成可重用、独立单元的基础概念。它们通过封装代码来帮助管理依赖、防止全局命名空间污染并提高可维护性。
TypeScript 完全支持标准的 ECMAScript (ES) 模块系统,该系统使用 import 和 export 关键字。对于浏览器和 Node.js 环境,这是构建 TypeScript 应用程序推荐的方法。
ES 模块:export 和 import
Section titled “ES 模块:export 和 import”任何包含顶级 import 或 export 语句的文件都被视为一个模块。在模块中声明的变量、函数、类等,除非明确导出,否则都是该模块的本地成员。
导出成员 (Exporting Members)
Section titled “导出成员 (Exporting Members)”你可以通过添加 export 关键字来导出声明。
// --- mathUtils.ts ---export const PI = 3.14159;
export function add(x: number, y: number): number { return x + y;}
export interface Point { x: number; y: number;}
// 默认导出(每个模块只能有一个)export default class Calculator { add(x: number, y: number): number { return x + y; } // ... 其他方法}你也可以单独导出成员:
// --- stringUtils.ts ---function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1);}
function reverse(str: string): string { return str.split('').reverse().join('');}
export { capitalize, reverse }; // 导出命名成员export { capitalize as cap }; // 以不同名称导出导入成员 (Importing Members)
Section titled “导入成员 (Importing Members)”使用 import 关键字从其他模块访问导出的成员。指定的路径通常是相对路径,或者可以由模块加载器/打包器(如 node_modules)解析。
// --- main.ts ---
// 导入命名导出import { add, PI, Point } from './mathUtils';
// 导入默认导出(可以使用任何名称)import MyCalculator from './mathUtils';
// 导入命名导出并使用别名import { capitalize as makeFirstLetterUpper, reverse } from './stringUtils';
// 将整个模块导入为一个对象import * as math from './mathUtils';
console.log(`Adding 5 and 3: ${add(5, 3)}`); // 输出: 8console.log(`PI is approx: ${PI}`); // 输出: 3.14159
const origin: Point = { x: 0, y: 0 };console.log('Origin:', origin);
const calc = new MyCalculator();console.log(`Calculator adds 10 and 20: ${calc.add(10, 20)}`); // 输出: 30
console.log(makeFirstLetterUpper('hello')); // 输出: Helloconsole.log(reverse('world')); // 输出: dlrow
console.log(`Accessing via module object: ${math.add(1, 1)}`); // 输出: 2console.log(`Default export via module object: ${new math.default().add(2,2)}`); // 输出: 4模块解析与执行 (Module Resolution and Execution)
Section titled “模块解析与执行 (Module Resolution and Execution)”模块如何被找到(解析)和执行取决于目标环境:
- 浏览器:现代浏览器直接支持 ES 模块,使用
<script type="module" src="...">。然而,为了兼容性、依赖管理和优化,开发者通常使用打包器 (bundlers),如 Webpack、Rollup、Parcel 或 Vite。打包器处理import/export语句,解析依赖,并为浏览器创建优化的 JavaScript 文件。 - **Node.js:**Node.js 内置支持 ES 模块(使用
.mjs文件或在package.json中设置"type": "module")和旧的 CommonJS 模块系统(require/module.exports)。TypeScript 可以使用tsconfig.json中的module选项(例如,"module": "NodeNext"或"module": "CommonJS")编译成这两种格式中的任何一种。
tsconfig.json 配置
Section titled “tsconfig.json 配置”与模块相关的 tsconfig.json 中的关键选项包括:
"module":指定编译后 JavaScript 输出的模块系统(例如,"ES2020"、"CommonJS"、"NodeNext")。"target":指定输出代码的 ECMAScript 版本(影响可用特性)。"moduleResolution":编译器如何查找模块(通常是"Node"或"NodeNext")。"outDir":编译后的 JavaScript 文件存放的目录。"rootDir":指定源文件的根目录(有助于在outDir中保持结构)。
命名空间 (Namespaces)(曾称内部模块)
Section titled “命名空间 (Namespaces)(曾称内部模块)”TypeScript 还有一个概念叫做 namespace。在 ES 模块成为标准之前,命名空间是 TypeScript 中用于将相关代码分组并避免污染全局作用域的主要方式。它们被编译成嵌套的 JavaScript 对象或立即执行函数表达式 (IIFEs)。
虽然 ES 模块现在是组织代码和管理依赖的标准,但命名空间仍然可能对以下情况有用:
- 在一个大型项目中组织内部代码,其中模块可能感觉过于细粒度。
- 为暴露全局对象的库构建声明文件 (
.d.ts)。 - 处理旧代码库或依赖于
--outFile编译的特定构建系统(尽管这现在不太常见了)。
命名空间语法 (Namespace Syntax)
Section titled “命名空间语法 (Namespace Syntax)”namespace Validation { export interface StringValidator { isAcceptable(s: string): boolean; }
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } }}
// 使用示例:let validator: Validation.StringValidator = new Validation.LettersOnlyValidator();console.log(validator.isAcceptable("HelloWorld")); // trueconsole.log(validator.isAcceptable("12345")); // false如果命名空间跨越多个文件,你可能需要 /// <reference path="..." /> 指令或使用 --outFile 编译器选项,但再说一次,ES 模块更自然地处理多文件组织。
建议 (Recommendation)
Section titled “建议 (Recommendation)”对于现代 TypeScript 开发,**强烈推荐使用 ES 模块(import/export)**来组织代码和管理依赖,而不是命名空间。理解命名空间主要是为了与旧代码的兼容性或像全局声明合并 (global declaration merging) 这样的特定用例。