一、TypeScript 导出机制详解
1. 基本导出方式
命名导出 (Named Exports)
typescript
// 导出单个声明
export const PI = 3.14;
export function calculateArea(radius: number): number {
return PI * radius * radius;
}
// 批量导出
const MAX_RADIUS = 100;
class Circle { /* ... */ }
export { MAX_RADIUS, Circle };
特点:
- 支持导出多个值
- 导入时需使用相同名称:
import { PI, calculateArea } from './math'
- 支持导出时重命名:
export { Circle as MyCircle }
默认导出 (Default Export)
typescript
// 默认导出(每个模块仅限一个)
export default class Calculator {
add(a: number, b: number): number {
return a + b;
}
}
特点:
- 导入时可任意命名:
import MyCalc from './Calculator'
- 适用于模块主要功能导出
- 可与命名导出共存
重新导出 (Re-export)
typescript
// 重新导出其他模块内容
export { PI } from './math';
export * as Geometry from './shapes';
export { default as Calc } from './Calculator';
作用:
- 创建模块入口文件
- 组织代码结构
- 隐藏实现细节
2. 类型导出
typescript
// 导出类型
export type Point = { x: number; y: number };
// 导出接口
export interface Shape {
area(): number;
}
// 导出类型与值
export class Vector implements Shape {
constructor(public x: number, public y: number) {}
area() { return 0; }
}
export type VectorType = Vector; // 导出类型别名
最佳实践:
- 使用
export type
明确导出类型 - 使用
import type
导入纯类型减少运行时开销 - 类型和实现分离:
export interface
+export class
3. 不同模块系统的导出差异
导出方式 | CommonJS | ES Modules | TypeScript 特有 |
---|---|---|---|
命名导出 | exports.name = value |
export const name = ... |
同 ES Modules |
默认导出 | module.exports = value |
export default value |
同 ES Modules |
混合导出 | exports.a = a; module.exports = b |
不支持混合 | 避免使用 |
导入方式 | const { a } = require() |
import { a } from '...' |
import a = require(...) |
类型导出 | 不支持 | export type T = ... |
同 ES Modules |
二、类型扩展的四种核心方法
1. 声明合并 (Declaration Merging)
适用场景:扩展接口或类
typescript
// 原始定义
interface Person {
name: string;
}
// 扩展属性
interface Person {
age: number;
greet(): void;
}
// 使用
const user: Person = {
name: "Alice",
age: 30,
greet() { console.log(`Hello, ${this.name}`) }
};
2. 模块增强 (Module Augmentation)
适用场景:扩展第三方库类型
typescript
// 扩展 moment.js
import 'moment';
declare module 'moment' {
interface Moment {
formatChinese(): string;
isWeekend(): boolean;
}
}
// 使用
import moment from 'moment';
moment().formatChinese();
3. 全局扩展 (Global Augmentation)
适用场景:添加全局类型
typescript
declare global {
interface Window {
myCustomAPI: {
version: string;
init(): void;
};
}
function debug(message: string): void;
}
// 使用
window.myCustomAPI.init();
debug("App started");
4. 类型工具扩展 (Utility Type Extension)
适用场景:增强 TypeScript 类型系统
typescript
// 扩展内置类型
interface Array<T> {
sum(): number;
first(): T | undefined;
}
// 声明新工具类型
type Nullable<T> = T | null;
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
三、扩展第三方库类型的完整流程
案例:为 MockJS 添加 XHR 属性
步骤1: 创建类型声明文件
typescript
// src/types/mockjs.d.ts
import 'mockjs';
declare module 'mockjs' {
interface Mock {
XHR: {
handlers: Record<string, Function>;
setup(options: { timeout?: number }): void;
mock(url: string, method: string, handler: Function): void;
clear(url?: string): void;
};
}
}
步骤2: 实现功能扩展
typescript
// src/utils/mockjs-xhr.ts
import Mock from 'mockjs';
const XHR = {
handlers: {},
setup(options: { timeout?: number } = {}) {
console.log(`Set timeout: ${options.timeout || 1000}ms`);
},
mock(url: string, method: string, handler: Function) {
const key = `${method.toUpperCase()} ${url}`;
this.handlers[key] = handler;
},
clear(url?: string) {
if (url) {
// 清除特定URL
} else {
this.handlers = {};
}
}
};
// 安全挂载
if (!Mock.XHR) {
Mock.XHR = XHR;
}
步骤3: 配置 tsconfig.json
json
{
"compilerOptions": {
"typeRoots": [
"./node_modules/@types",
"./src/types" // 包含自定义类型
],
"types": ["mockjs", "mockjs-xhr"],
"skipLibCheck": true
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts"
]
}
步骤4: 使用扩展功能
typescript
import Mock from 'mockjs';
Mock.XHR.setup({ timeout: 2000 });
Mock.XHR.mock('/api/users', 'GET', () => {
return Mock.mock({ 'users|5': [{ id: '@id' }] });
});
四、高级类型扩展技巧
1. 条件类型扩展
typescript
type ApiResponse<T> =
T extends 'user' ? { id: string; name: string } :
T extends 'product' ? { sku: string; price: number } :
never;
declare module 'my-api' {
function fetchData<T extends 'user' | 'product'>(type: T): ApiResponse<T>;
}
2. 类型守卫增强
typescript
interface Cat { meow(): void; }
interface Dog { bark(): void; }
declare module 'animals' {
function isCat(animal: unknown): animal is Cat;
function isDog(animal: unknown): animal is Dog;
}
3. 泛型约束扩展
typescript
// 扩展Promise类型
interface Promise<T> {
withTimeout(ms: number, errorMsg?: string): Promise<T>;
}
// 实现
Promise.prototype.withTimeout = function(ms, errorMsg = "Timeout") {
return Promise.race([
this,
new Promise((_, reject) =>
setTimeout(() => reject(new Error(errorMsg)), ms)
]);
};
五、最佳实践与注意事项
类型扩展最佳实践
实践 | 说明 | 示例 |
---|---|---|
优先使用模块增强 | 避免全局污染 | declare module 'lib' { ... } |
创建专用类型目录 | 统一管理扩展类型 | src/@types/ 或 src/types/ |
使用JSDoc文档注释 | 增强IDE提示 | /** Setup XHR options */ |
版本兼容检查 | 避免版本冲突 | if (lib.version > '2.0') { ... } |
分离类型与实现 | 保持声明文件纯净 | .d.ts 文件不含实现代码 |
常见问题解决方案
问题1:类型扩展未生效
- 检查
tsconfig.json
的include
和typeRoots
- 确保声明文件扩展名为
.d.ts
- 重启TS服务器:VSCode中
> TypeScript: Restart TS server
问题2:与原始类型冲突
- 使用更精确的类型约束
- 通过条件类型避免冲突
- 提交PR到DefinitelyTyped修复官方类型
问题3:生产环境排除扩展
json
// tsconfig.prod.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": ["mockjs"] // 排除mockjs-xhr
}
}
六、总结
TypeScript 的导出系统提供了灵活的模块组织方案:
- 命名导出 适用于导出多个实体
- 默认导出 适合作为模块主要功能
- 类型导出 应使用
export type
明确声明
类型扩展是TS的强大特性,可通过:
- 声明合并 扩展已有接口
- 模块增强 补全第三方库类型
- 全局扩展 添加全局类型
- 工具类型 增强类型系统
遵循最佳实践:
- 将类型扩展放在专用目录
- 使用模块增强替代全局扩展
- 为扩展添加完善的文档注释
- 做好生产环境配置管理
掌握这些技术能显著提升代码的类型安全性和可维护性,使TypeScript真正发挥其强大威力。