Typescript学习教程,从入门到精通,TypeScript 名称空间与模块语法知识点及案例(14)
TypeScript 名称空间与模块语法知识点及案例
本文将详细介绍 TypeScript 中的名称空间(Namespaces)和模块(Modules),涵盖其语法、特性及实际应用,并通过案例代码进行说明。
一、名称空间(Namespaces)
1.1 定义名称空间和导出资源
名称空间用于组织代码,避免全局命名冲突。通过 namespace
关键字定义,并通过 export
关键字导出需要公开的成员。
语法:
namespace 名称空间名称 {export 成员1;export 成员2;// 其他成员
}
示例:
// 定义一个名为 MyNamespace 的名称空间
namespace MyNamespace {// 导出一个变量export const PI: number = 3.14159;// 导出一个函数export function calculateCircumference(diameter: number): number {return PI * diameter;}// 一个内部使用的类,不导出class Helper {static helperMethod(): void {console.log("Helper method called.");}}// 使用内部类Helper.helperMethod();
}// 使用名称空间中的导出成员
console.log(MyNamespace.PI); // 输出: 3.14159
console.log(MyNamespace.calculateCircumference(5)); // 输出: 15.70795
1.2 名称空间嵌套
名称空间可以嵌套,以组织更复杂的代码结构。
示例:
namespace MyApp {export namespace Models {export class User {constructor(public name: string, public age: number) {}}}export namespace Services {export function getUserName(user: Models.User): string {return user.name;}}
}// 使用嵌套的名称空间
const user = new MyApp.Models.User("Alice", 30);
console.log(MyApp.Services.getUserName(user)); // 输出: Alice
1.3 跨文件访问名称空间内资源
为了在多个文件中使用同一个名称空间,需要使用 /// <reference path="..." />
指令引用对应的声明文件。
文件结构:
MyNamespace.ts
MyApp.ts
MyNamespace.ts:
namespace MyNamespace {export const version: string = "1.0.0";
}
MyApp.ts:
/// <reference path="MyNamespace.ts" />namespace MyNamespace {export function printVersion(): void {console.log(`Version: ${version}`);}
}// 使用名称空间中的成员
MyNamespace.printVersion(); // 输出: Version: 1.0.0
编译时:
使用 tsc --outFile MyApp.js MyApp.ts MyNamespace.ts
编译为单个文件,或使用模块加载器(如 RequireJS)来处理。
二、模块(Modules)
模块是更现代、更强大的代码组织方式,基于 ES6 模块标准,支持静态分析和更好的依赖管理。
2.1 普通脚本资源全局可见
默认情况下,使用 import
或 export
的文件被视为模块,否则被视为全局脚本。
示例:
// globals.ts
const globalVar = "I am global";function globalFunction() {console.log("Global function called.");
}// 未使用 export 或 import,globalVar 和 globalFunction 在全局作用域中可见
注意: 尽量避免使用全局脚本,使用模块来管理依赖。
2.2 模块导出默认资源
使用 export default
导出模块的默认成员。
示例:
// mathUtils.ts
export default function add(a: number, b: number): number {return a + b;
}// 使用默认导出
import add from "./mathUtils";console.log(add(2, 3)); // 输出: 5
2.3 模块导出多个资源
使用 export
导出多个成员。
示例:
// mathUtils.ts
export const PI: number = 3.14159;export function multiply(a: number, b: number): number {return a * b;
}export class Calculator {add(a: number, b: number): number {return a + b;}
}// 使用多个导出
import { PI, multiply, Calculator } from "./mathUtils";console.log(PI); // 输出: 3.14159
console.log(multiply(2, 3)); // 输出: 6
const calc = new Calculator();
console.log(calc.add(4, 5)); // 输出: 9
2.4 同时导出默认资源和普通资源
一个模块可以同时有默认导出和命名导出。
示例:
// logger.ts
export default function log(message: string): void {console.log(message);
}export const ERROR_LEVEL: string = "ERROR";export function logError(error: string): void {console.error(`${ERROR_LEVEL}: ${error}`);
}// 使用同时导出的成员
import log, { ERROR_LEVEL, logError } from "./logger";log("This is a log message.");
logError("This is an error message.");
console.log(ERROR_LEVEL); // 输出: ERROR
2.5 导入变量的只读特征
导入的变量是只读的,不能被重新赋值。
示例:
// constants.ts
export const MAX_USERS: number = 100;// main.ts
import { MAX_USERS } from "./constants";console.log(MAX_USERS); // 输出: 100// 尝试重新赋值会报错
// MAX_USERS = 200; // 编译错误: Cannot assign to 'MAX_USERS' because it is a read-only imported binding.
2.6 导出导入的其他语法
2.6.1 重命名导出和导入
导出时重命名:
// mathUtils.ts
const add = (a: number, b: number): number => a + b;
const multiply = (a: number, b: number): number => a * b;export { add as addition, multiply };
导入时重命名:
import { addition, multiply as mult } from "./mathUtils";console.log(addition(2, 3)); // 输出: 5
console.log(mult(2, 3)); // 输出: 6
2.6.2 整体导入
// mathUtils.ts
export const PI: number = 3.14159;
export function add(a: number, b: number): number {return a + b;
}// main.ts
import * as MathUtils from "./mathUtils";console.log(MathUtils.PI); // 输出: 3.14159
console.log(MathUtils.add(2, 3)); // 输出: 5
2.6.3 默认导入与命名导入结合
// logger.ts
export default function log(message: string): void {console.log(message);
}export const ERROR_LEVEL: string = "ERROR";// main.ts
import log, { ERROR_LEVEL as EL } from "./logger";log("Hello");
console.log(EL); // 输出: ERROR
2.7 CommonJS 规范下模块的导出和导入
虽然 TypeScript 主要使用 ES6 模块语法,但也可以使用 CommonJS 语法,通过 module
选项配置。
导出:
// mathUtils.js
function add(a, b) {return a + b;
}module.exports = { add };
导入:
// main.js
const mathUtils = require("./mathUtils");
console.log(mathUtils.add(2, 3)); // 输出: 5
注意: 在 TypeScript 中,推荐使用 ES6 模块语法,并通过 tsc
编译为 CommonJS 格式。
三、实战闯关——名称空间与模块
3.1 名称空间实战
目标: 使用名称空间组织一个简单的图书管理系统。
代码:
// libraryNamespace.ts
namespace Library {export interface Book {title: string;author: string;pages: number;}export class Catalog {private books: Book[] = [];addBook(book: Book): void {this.books.push(book);console.log(`Book ${book.title} added to catalog.`);}listBooks(): void {console.log("Catalog:");this.books.forEach(book => {console.log(`- ${book.title} by ${book.author}, ${book.pages} pages`);});}}
}// 使用名称空间
const catalog = new Library.Catalog();
catalog.addBook({ title: "1984", author: "George Orwell", pages: 328 });
catalog.addBook({ title: "To Kill a Mockingbird", author: "Harper Lee", pages: 281 });
catalog.listBooks();
输出:
Book 1984 added to catalog.
Book To Kill a Mockingbird added to catalog.
Catalog:
- 1984 by George Orwell, 328 pages
- To Kill a Mockingbird by Harper Lee, 281 pages
3.2 模块实战
目标: 使用模块构建一个简单的用户管理系统。
文件结构:
models/User.ts
services/UserService.ts
main.ts
models/User.ts:
export interface User {id: number;name: string;email: string;
}export class UserManager {private users: User[] = [];addUser(user: User): void {this.users.push(user);console.log(`User ${user.name} added.`);}getUserById(id: number): User | undefined {return this.users.find(user => user.id === id);}
}
services/UserService.ts:
import { User, UserManager } from "../models/User";export function printUser(user: User): void {console.log(`User ID: ${user.id}, Name: ${user.name}, Email: ${user.email}`);
}export const userManager = new UserManager();
main.ts:
import { printUser, userManager } from "./services/UserService";
import { User } from "./models/User";// 添加用户
const alice: User = { id: 1, name: "Alice", email: "alice@example.com" };
userManager.addUser(alice);
printUser(alice);// 获取用户
const user = userManager.getUserById(1);
if (user) {printUser(user);
} else {console.log("User not found.");
}
输出:
User Alice added.
User ID: 1, Name: Alice, Email: alice@example.com
User ID: 1, Name: Alice, Email: alice@example.com
3.3 综合实战
目标: 结合名称空间和模块,构建一个包含用户和图书管理的系统。
文件结构:
library/LibraryNamespace.ts
models/User.ts
services/UserService.ts
main.ts
library/LibraryNamespace.ts:
namespace Library {export interface Book {id: number;title: string;author: string;pages: number;}export class Catalog {private books: Book[] = [];addBook(book: Book): void {this.books.push(book);console.log(`Book ${book.title} added to catalog.`);}listBooks(): void {console.log("Catalog:");this.books.forEach(book => {console.log(`- ${book.title} by ${book.author}, ${book.pages} pages`);});}}
}
models/User.ts:
export interface User {id: number;name: string;email: string;
}export class UserManager {private users: User[] = [];addUser(user: User): void {this.users.push(user);console.log(`User ${user.name} added.`);}getUserById(id: number): User | undefined {return this.users.find(user => user.id === id);}
}
services/UserService.ts:
import { User, UserManager } from "../models/User";
import { Library } from "../library/LibraryNamespace";export function printUser(user: User): void {console.log(`User ID: ${user.id}, Name: ${user.name}, Email: ${user.email}`);
}export const userManager = new UserManager();export function addBookToCatalog(book: Library.Book): void {const catalog = new Library.Catalog();catalog.addBook(book);
}
main.ts:
import { printUser, userManager, addBookToCatalog } from "./services/UserService";
import { Library } from "./library/LibraryNamespace";// 添加用户
const bob: User = { id: 2, name: "Bob", email: "bob@example.com" };
userManager.addUser(bob);
printUser(bob);// 添加图书
const book: Library.Book = { id: 1, title: "The Catcher in the Rye", author: "J.D. Salinger", pages: 277 };
addBookToCatalog(book);// 列出图书
const catalog = new Library.Catalog();
catalog.listBooks();
输出:
User Bob added.
User ID: 2, Name: Bob, Email: bob@example.com
Book The Catcher in the Rye added to catalog.
Catalog:
- The Catcher in the Rye by J.D. Salinger, 277 pages
总结
- 名称空间适用于简单的代码组织,避免全局命名冲突,但在大型项目中使用模块更为合适。
- 模块基于 ES6 标准,支持静态分析、更好的依赖管理和代码重用,是现代 TypeScript 项目的首选。
- 结合使用名称空间和模块,可以构建结构清晰、易于维护的复杂应用程序。
通过掌握名称空间和模块的使用,开发者可以有效地组织代码,提升项目的可维护性和可扩展性。