代码迁移的挑战
代码迁移是开发中最头疼的工作之一。不管是 JavaScript 到 TypeScript、React Class 到 Hooks,还是 Python 2 到 Python 3,都面临同样的问题:
- 工作量大,容易遗漏
- 需要同时理解新旧两套技术
- 迁移过程中容易引入 Bug
- 测试覆盖可能不完整
AI 在这个场景下特别有价值——它同时精通多种语言和框架,能快速完成机械性的转换工作,让我们专注于业务逻辑的验证。
通用迁移提示词模板
你是一个代码迁移专家。请将以下代码从 [源技术] 迁移到 [目标技术]。
源代码:
```[语言]
[代码]
迁移要求:
- 保持功能完全一致
- 遵循 [目标技术] 的最佳实践和惯用写法
- 不要简单翻译,要用目标技术的”原生”方式实现
- 保留原有的注释(翻译为目标语言的注释风格)
- 标注迁移中需要人工确认的地方
请输出:
- 迁移后的完整代码
- 迁移说明(改了什么,为什么这样改)
- 需要注意的差异点
- 建议的测试用例
---
## 场景一:JavaScript → TypeScript
### 提示词
请将以下 JavaScript 代码迁移到 TypeScript。
代码:
[JS 代码]
要求:
- 添加完整的类型注解(不要用 any)
- 使用 interface 定义数据结构
- 使用 enum 替代魔法字符串
- 使用 strict 模式兼容的写法
- 处理可能的 null/undefined
tsconfig 配置:strict: true
### 实际示例
输入:
```javascript
function fetchUsers(options) {
const { page = 1, size = 20, role } = options || {};
return fetch(`/api/users?page=${page}&size=${size}${role ? `&role=${role}` : ''}`)
.then(res => {
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
})
.then(data => {
return data.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`,
isAdmin: user.role === 'admin',
}));
});
}
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
AI 输出:
// 类型定义
interface FetchUsersOptions {
page?: number;
size?: number;
role?: UserRole;
}
enum UserRole {
Admin = 'admin',
User = 'user',
Moderator = 'moderator',
}
interface RawUser {
id: number;
firstName: string;
lastName: string;
email: string;
role: UserRole;
}
interface User extends RawUser {
fullName: string;
isAdmin: boolean;
}
// 迁移后的函数
async function fetchUsers(options?: FetchUsersOptions): Promise<User[]> {
const { page = 1, size = 20, role } = options ?? {};
const params = new URLSearchParams({
page: String(page),
size: String(size),
});
if (role) {
params.set('role', role);
}
const res = await fetch(`/api/users?${params.toString()}`);
if (!res.ok) {
throw new Error(`Failed to fetch users: ${res.status}`);
}
const data: RawUser[] = await res.json();
return data.map((user): User => ({
...user,
fullName: `${user.firstName} ${user.lastName}`,
isAdmin: user.role === UserRole.Admin,
}));
}
function debounce<T extends (...args: unknown[]) => unknown>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout> | undefined;
return function (this: unknown, ...args: Parameters<T>): void {
if (timer !== undefined) {
clearTimeout(timer);
}
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
迁移说明:
options || {}改为options ?? {},更精确地处理 null/undefined- Promise chain 改为 async/await,更符合现代 TypeScript 风格
- URL 拼接改为 URLSearchParams,更安全
- debounce 使用泛型保留原函数的类型信息
- 魔法字符串
'admin'改为 enumUserRole.Admin
场景二:React Class → Hooks
提示词
请将以下 React Class 组件迁移到函数组件 + Hooks。
代码:
```jsx
[Class 组件代码]
要求:
- 使用 useState、useEffect、useCallback、useMemo 等 Hooks
- 生命周期方法正确映射到 useEffect
- this.setState 的回调逻辑要正确处理
- 保持 ref 的使用方式正确
- 使用 TypeScript(如果原代码是 TS)
### 实际示例
输入:
```jsx
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = {
user: null,
loading: true,
error: null,
};
this.abortController = null;
}
componentDidMount() {
this.fetchUser();
}
componentDidUpdate(prevProps) {
if (prevProps.userId !== this.props.userId) {
this.fetchUser();
}
}
componentWillUnmount() {
if (this.abortController) {
this.abortController.abort();
}
}
async fetchUser() {
this.setState({ loading: true, error: null });
if (this.abortController) {
this.abortController.abort();
}
this.abortController = new AbortController();
try {
const res = await fetch(`/api/users/${this.props.userId}`, {
signal: this.abortController.signal,
});
const user = await res.json();
this.setState({ user, loading: false });
} catch (err) {
if (err.name !== 'AbortError') {
this.setState({ error: err.message, loading: false });
}
}
}
render() {
const { user, loading, error } = this.state;
if (loading) return <div>加载中...</div>;
if (error) return <div>错误:{error}</div>;
if (!user) return null;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
}
AI 输出:
interface User {
name: string;
email: string;
}
interface UserProfileProps {
userId: number;
}
function UserProfile({ userId }: UserProfileProps) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const abortController = new AbortController();
async function fetchUser() {
setLoading(true);
setError(null);
try {
const res = await fetch(`/api/users/${userId}`, {
signal: abortController.signal,
});
const data: User = await res.json();
setUser(data);
setLoading(false);
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
setError(err.message);
setLoading(false);
}
}
}
fetchUser();
// cleanup:组件卸载或 userId 变化时取消请求
return () => abortController.abort();
}, [userId]);
if (loading) return <div>加载中...</div>;
if (error) return <div>错误:{error}</div>;
if (!user) return null;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
迁移说明:
componentDidMount+componentDidUpdate合并为一个useEffectcomponentWillUnmount的清理逻辑放在useEffect的 return 中AbortController从实例变量变为useEffect内的局部变量,生命周期更清晰- 依赖数组
[userId]自动处理了componentDidUpdate的比较逻辑
场景三:Vue 2 → Vue 3
提示词
请将以下 Vue 2 Options API 组件迁移到 Vue 3 Composition API。
代码:
```vue
[Vue 2 组件]
要求:
- 使用
- 使用 ref/reactive 替代 data
- 使用 computed 替代 computed 属性
- 使用 watch/watchEffect 替代 watch
- 生命周期钩子正确映射
- 使用 TypeScript
### 生命周期映射表
| Vue 2 | Vue 3 Composition API |
|-------|----------------------|
| beforeCreate | setup() 本身 |
| created | setup() 本身 |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
---
## 场景四:Express → Fastify
### 提示词
请将以下 Express 应用迁移到 Fastify。
代码:
[Express 代码]
要求:
- 使用 Fastify 的插件系统
- 使用 JSON Schema 做请求验证(替代 express-validator)
- 使用 Fastify 的错误处理机制
- 保持路由结构一致
- 使用 TypeScript
### 关键差异对照
| Express | Fastify |
|---------|---------|
| `app.use(middleware)` | `fastify.register(plugin)` |
| `req.body` | `request.body`(自动解析) |
| `res.json()` | `reply.send()` |
| `express-validator` | JSON Schema validation |
| `app.use(errorHandler)` | `fastify.setErrorHandler()` |
| `express.Router()` | `fastify.register()` with prefix |
---
## 场景五:Python 2 → Python 3
### 提示词
请将以下 Python 2 代码迁移到 Python 3。
代码:
[Python 2 代码]
要求:
- 处理 print 语句 → print 函数
- 处理 unicode/str 差异
- 处理 dict.keys()/values()/items() 返回类型变化
- 处理 integer division 差异
- 使用 Python 3 的新特性(f-string、type hints、pathlib 等)
- 标注需要特别注意的兼容性问题
### 常见迁移点
```python
# Python 2 # Python 3
print "hello" print("hello")
unicode("text") "text" # str 默认是 unicode
dict.has_key("k") "k" in dict
dict.iteritems() dict.items()
range(10) # 返回 list range(10) # 返回 iterator
5 / 2 # = 2 5 / 2 # = 2.5, 5 // 2 = 2
except Exception, e: except Exception as e:
raw_input() input()
场景六:迁移规划
在动手迁移之前,先让 AI 帮你做规划:
请帮我制定从 [源技术] 到 [目标技术] 的迁移计划。
项目信息:
- 项目规模:[文件数/代码行数]
- 当前技术栈:[详细描述]
- 目标技术栈:[详细描述]
- 团队规模:[人数]
- 时间约束:[截止日期]
请输出:
1. 迁移策略(大爆炸 vs 渐进式)
2. 分阶段计划
3. 每个阶段的工作量估算
4. 风险评估和应对方案
5. 测试策略
6. 回滚方案
输出示例
迁移计划:JavaScript → TypeScript
策略:渐进式迁移(推荐)
阶段 1:基础设施(1 周)
- 配置 tsconfig.json(allowJs: true)
- 配置 ESLint + TypeScript 规则
- 添加 @types 依赖
- 工作量:1 人天
阶段 2:类型定义(1 周)
- 创建 types/ 目录,定义核心数据类型
- 为第三方库添加类型声明
- 工作量:2-3 人天
阶段 3:核心模块迁移(2 周)
- 优先迁移:工具函数、API 层、数据模型
- 每个文件:.js → .ts,添加类型注解
- 工作量:5-8 人天
阶段 4:组件迁移(3 周)
- 从叶子组件开始,逐步向上
- .jsx → .tsx
- 工作量:8-12 人天
阶段 5:严格模式(1 周)
- 开启 strict: true
- 消除所有 any 类型
- 工作量:3-5 人天
风险:
- 第三方库缺少类型定义 → 手写 .d.ts
- 隐式 any 太多 → 先用 @ts-ignore,后续逐步修复
- 构建时间增加 → 使用 esbuild 或 swc
场景七:测试保留
迁移过程中最怕的就是引入 Bug。确保测试跟着迁移:
请在迁移以下代码的同时,迁移对应的测试。
源代码:
```[语言]
[代码]
源测试:
[测试代码]
要求:
- 迁移代码到 [目标技术]
- 迁移测试到 [目标测试框架]
- 确保测试覆盖率不降低
- 如果迁移引入了新的边界情况,添加新的测试
---
## 批量迁移技巧
### 1. 先迁移类型定义
请分析以下项目的代码,提取所有需要定义的 TypeScript 类型。 只输出类型定义文件(.d.ts),不要迁移实际代码。
文件列表: [文件列表和关键代码片段]
### 2. 从叶子节点开始
请分析以下项目的依赖关系,给出迁移顺序建议。 原则:先迁移没有内部依赖的模块(叶子节点),再迁移依赖它们的模块。
模块列表: [模块列表和依赖关系]
### 3. 迁移检查清单
每个文件迁移后,用这个提示词做检查:
请检查以下迁移是否正确。
原始代码([源技术]): [原始代码]
迁移后代码([目标技术]): [迁移后代码]
请检查:
- 功能是否完全一致
- 是否遗漏了边界情况处理
- 是否使用了目标技术的最佳实践
- 是否有类型安全问题
- 是否有性能差异
---
## 总结
| 迁移场景 | 难度 | AI 辅助价值 |
|---------|------|-----------|
| JS → TS | 中 | 高(类型推断是 AI 强项) |
| React Class → Hooks | 中 | 高(模式转换很机械) |
| Vue 2 → Vue 3 | 中 | 高(API 映射明确) |
| Express → Fastify | 低 | 中(差异不大) |
| Python 2 → 3 | 低 | 中(大部分是语法变化) |
| 跨语言迁移 | 高 | 中(需要人工验证逻辑) |
AI 能帮你完成 70-80% 的机械性迁移工作,但剩下的 20-30%——业务逻辑验证、边界情况处理、性能测试——仍然需要人工把关。
> 代码迁移就像搬家:AI 帮你打包和搬运,但哪些东西该扔、哪些该留、新家怎么布置,还是得你自己决定。 相关文章
评论
加载中...
评论
加载中...