理解命名空间、模块、声明文件
命名空间(Namespace)
命名空间是 TypeScript 提供的一种组织代码的方式,用于避免全局作用域中的命名冲突。它可以将相关的代码组织在一起,形成一个独立的作用域。
基本语法
typescript
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string): boolean {
return /^[A-Za-z]+$/.test(s);
}
}
// 未导出的内容在命名空间外部无法访问
const defaultLength = 5;
}
嵌套命名空间
typescript
namespace Shapes {
export namespace Polygons {
export class Triangle {}
export class Square {}
}
}
// 使用
let sq = new Shapes.Polygons.Square();
别名
typescript
import polygons = Shapes.Polygons;
let sq = new polygons.Square();
模块(Module)
模块是 TypeScript/ES6 中更现代的代码组织方式,每个文件就是一个模块。
导出方式
typescript
// 单个导出
export interface StringValidator {
isAcceptable(s: string): boolean;
}
// 默认导出
export default class DefaultValidator {
// ...
}
// 批量导出
const validator1 = {
/* ... */
};
const validator2 = {
/* ... */
};
export { validator1, validator2 };
// 重命名导出
export { validator1 as mainValidator };
导入方式
typescript
// 基本导入
import { StringValidator } from './validators';
// 默认导入
import DefaultValidator from './validators';
// 全部导入
import * as validators from './validators';
// 重命名导入
import { mainValidator as validator } from './validators';
声明文件(.d.ts)
声明文件用于为 JavaScript 库提供类型信息,通常以 .d.ts
为扩展名。
全局声明
typescript
// global.d.ts
declare global {
interface Window {
customProperty: string;
}
}
// 声明全局变量
declare const VERSION: string;
// 声明全局函数
declare function getData(id: number): Promise<any>;
// 声明全局类
declare class MyGlobalClass {
constructor(options: MyGlobalClass.Options);
method(): void;
}
模块声明
typescript
// lodash.d.ts
declare module 'lodash' {
export function chunk<T>(array: T[], size?: number): T[][];
export function debounce(
func: Function,
wait?: number,
options?: DebounceOptions
): Function;
}
命名空间声明
typescript
// jquery.d.ts
declare namespace $ {
function ajax(url: string, settings?: any): void;
interface JQueryStatic {
get(url: string): Promise<any>;
post(url: string, data: any): Promise<any>;
}
}
三斜线指令(Triple-Slash Directives)
三斜线指令是包含单个 XML 标签的单行注释。它们只能出现在文件的顶部,并且仅在声明文件中使用。
1. 引用路径 (path)
typescript
/// <reference path="./other-file.d.ts" />
作用:
- 声明文件间的依赖关系
- 指定编译时需要包含的文件
- 多个声明文件合并
使用场景:
typescript
// shapes.d.ts
interface Shape {
color: string;
}
// circle.d.ts
/// <reference path="shapes.d.ts" />
interface Circle extends Shape {
radius: number;
}
2. 引用类型 (types)
typescript
/// <reference types="node" />
作用:
- 声明对 @types 包的依赖
- 引入第三方库的类型定义
- 用于声明文件而不是源文件
使用场景:
typescript
/// <reference types="jquery" />
declare function $(selector: string): JQuery;
3. 引用库 (lib)
typescript
/// <reference lib="es2015" />
作用:
- 引入内置库的类型定义
- 类似于 tsconfig.json 中的 lib 选项
- 在特定文件中启用特定的库
4. 引用 no-default-lib
typescript
/// <reference no-default-lib="true" />
作用:
- 标记文件为默认库
- 告诉编译器不要包含默认库(如 lib.d.ts)
- 通常用于自定义运行时环境
5. amd-module
typescript
/// <amd-module name="nameOfModule" />
作用:
- 给生成的 AMD 模块命名
- 用于 AMD 模块系统的兼容性
使用注意事项
- 位置要求
typescript
// 正确
/// <reference path="..." />
import { something } from './module';
// 错误
import { something } from './module';
/// <reference path="..." /> // 不能在其他语句后面
- 优先级
typescript
// tsconfig.json 中的配置优先级高于三斜线指令
{
"compilerOptions": {
"types": ["node", "jest"]
}
}
- 模块解析
typescript
// 相对路径
/// <reference path="./types.d.ts" />
// 包引用
/// <reference types="node" />
最佳实践
- 现代项目建议
typescript
// 推荐使用 package.json 和 tsconfig.json 管理依赖
{
"dependencies": {
"@types/node": "^14.14.31"
}
}
- 声明文件组织
typescript
// index.d.ts
/// <reference path="./interfaces.d.ts" />
/// <reference path="./types.d.ts" />
/// <reference path="./constants.d.ts" />
export * from './interfaces';
export * from './types';
- 避免过度使用
typescript
// 不推荐
/// <reference path="./file1.d.ts" />
/// <reference path="./file2.d.ts" />
/// <reference path="./file3.d.ts" />
// 推荐使用模块导入
import { Type1 } from './file1';
import { Type2 } from './file2';
常见问题解决
- 路径解析问题
typescript
// 使用相对路径
/// <reference path="../typings/jquery.d.ts" />
// 使用绝对路径
/// <reference path="/user/typescript/typings/jquery.d.ts" />
- 类型冲突
typescript
// 通过命名空间解决
/// <reference path="lib1.d.ts" />
/// <reference path="lib2.d.ts" />
declare namespace MyLib {
// 避免冲突的类型定义
}
- 循环依赖
typescript
// a.d.ts
/// <reference path="b.d.ts" />
interface A {
b: B;
}
// b.d.ts
/// <reference path="a.d.ts" /> // 避免这种循环引用
interface B {
a: A;
}
总结
命名空间使用建议
- 避免在现代应用中过度使用命名空间
- 适用于组织大型应用中的工具函数或内部模块
- 命名空间嵌套不要超过两层
- 使用 export 谨慎导出必要的内容
模块使用建议
- 一个文件一个模块,保持职责单一
- 使用明确的导入导出语句
- 避免使用
export default
- 合理使用路径别名简化导入路径
声明文件编写建议
- 为所有公共 API 提供完整的类型信息
- 使用 JSDoc 注释提供详细文档
- 遵循 DefinitelyTyped 的规范
- 使用
declare
关键字声明全局内容