遗留 TypeScript 代码重构:高级技巧

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么遗留 TypeScript 代码需要特殊方法

处理遗留代码是每个开发者不可避免的现实,尤其是在大型项目中。这类代码通常编写时缺乏严格的类型化,到处使用 any,并且是一个依赖关系错综复杂的混乱体。简单的重构在这里行不通——需要系统性的、高级的方法。

在本文中,我们将探讨超出基础指南范围的遗留 TypeScript 代码重构策略。您将学习如何安全地引入严格的类型化,使用设计模式隔离更改,以及利用编译器的能力来自动化日常任务。



策略 1:通过“类型桥接”逐步引入严格类型化

遗留代码的主要问题之一是全面使用 any。试图一次性将所有 any 替换为具体类型会导致数百个错误并瘫痪开发。相反,我们使用 “类型桥接” 技术。

该方法的核心:我们不立即重写整个模块,而是创建中间类型桥,逐步取代 any。



示例:为“灰色”模块添加类型

假设我们有一个用于处理用户的旧模块:

// legacyModule.tsexport function processUser(data: any): any {  // ... 大量难以阅读的代码  return { id: data.id, name: data.name, age: data.age };}

我们不立即为整个函数添加类型,而是创建 UserData 和 User:

// types.tsexport interface UserData {  id: number;  name: string;  age?: number; // 字段可能缺失}

export interface User { id: number; fullName: string; isAdult: boolean;}

现在使用这些类型,但保留旧签名以实现向后兼容:

// legacyModule.ts (重构步骤 1)import { UserData, User } from './types';

export function processUser(data: UserData): User { const isAdult = data.age ? data.age >= 18 : false; return { id: data.id, fullName: data.name, isAdult, };}

// 为兼容性保留旧签名export function processUserLegacy(data: any): any { return processUser(data as UserData);}

在所有消费者迁移到新函数后,删除 processUserLegacy。这种方法最大限度地降低了破坏依赖关系的风险。



策略 2:使用“适配器”模式隔离“脏”依赖

遗留代码通常与外部库、全局状态或过时的 API 紧密耦合。为了安全地进行重构,需要隔离这些依赖关系。最好的工具是 “适配器”模式 与接口的结合。



示例:隔离过时的 API

// oldApi.ts (遗留代码)export function fetchOldData(callback: (data: any) => void): void {  // 使用回调的旧 API  setTimeout(() => callback({ value: 42 }), 100);}

为新的方法(基于 Promise)创建接口和适配器:

// apiAdapter.tsimport { fetchOldData } from './oldApi';

export interface IDataFetcher { fetchData(): Promise<{ value: number }>;}

export class LegacyApiAdapter implements IDataFetcher { fetchData(): Promise<{ value: number }> { return new Promise((resolve, reject) => { fetchOldData((data) => { if (data) { resolve(data); } else { reject(new Error('No data')); } }); }); }}

现在所有新代码都使用 IDataFetcher。当您完全重写旧 API 时,只需替换适配器的实现,而无需修改其他代码。这可以将回归风险降至最低。



策略 3:

博客

书籍推荐