提示工程 | | 约 25 分钟 | 9,835 字

代码迁移提示词:跨语言与跨框架

用 AI 辅助 JavaScript 到 TypeScript、React Class 到 Hooks 等迁移场景

代码迁移的挑战

代码迁移是开发中最头疼的工作之一。不管是 JavaScript 到 TypeScript、React Class 到 Hooks,还是 Python 2 到 Python 3,都面临同样的问题:

  1. 工作量大,容易遗漏
  2. 需要同时理解新旧两套技术
  3. 迁移过程中容易引入 Bug
  4. 测试覆盖可能不完整

AI 在这个场景下特别有价值——它同时精通多种语言和框架,能快速完成机械性的转换工作,让我们专注于业务逻辑的验证。


通用迁移提示词模板

你是一个代码迁移专家。请将以下代码从 [源技术] 迁移到 [目标技术]。

源代码:
```[语言]
[代码]

迁移要求:

  1. 保持功能完全一致
  2. 遵循 [目标技术] 的最佳实践和惯用写法
  3. 不要简单翻译,要用目标技术的”原生”方式实现
  4. 保留原有的注释(翻译为目标语言的注释风格)
  5. 标注迁移中需要人工确认的地方

请输出:

  1. 迁移后的完整代码
  2. 迁移说明(改了什么,为什么这样改)
  3. 需要注意的差异点
  4. 建议的测试用例

---

## 场景一:JavaScript → TypeScript

### 提示词

请将以下 JavaScript 代码迁移到 TypeScript。

代码:

[JS 代码]

要求:

  1. 添加完整的类型注解(不要用 any)
  2. 使用 interface 定义数据结构
  3. 使用 enum 替代魔法字符串
  4. 使用 strict 模式兼容的写法
  5. 处理可能的 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' 改为 enum UserRole.Admin

场景二:React Class → Hooks

提示词

请将以下 React Class 组件迁移到函数组件 + Hooks。

代码:
```jsx
[Class 组件代码]

要求:

  1. 使用 useState、useEffect、useCallback、useMemo 等 Hooks
  2. 生命周期方法正确映射到 useEffect
  3. this.setState 的回调逻辑要正确处理
  4. 保持 ref 的使用方式正确
  5. 使用 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 合并为一个 useEffect
  • componentWillUnmount 的清理逻辑放在 useEffect 的 return 中
  • AbortController 从实例变量变为 useEffect 内的局部变量,生命周期更清晰
  • 依赖数组 [userId] 自动处理了 componentDidUpdate 的比较逻辑

场景三:Vue 2 → Vue 3

提示词

请将以下 Vue 2 Options API 组件迁移到 Vue 3 Composition API。

代码:
```vue
[Vue 2 组件]

要求:

  1. 使用
  2. 使用 ref/reactive 替代 data
  3. 使用 computed 替代 computed 属性
  4. 使用 watch/watchEffect 替代 watch
  5. 生命周期钩子正确映射
  6. 使用 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 代码]

要求:

  1. 使用 Fastify 的插件系统
  2. 使用 JSON Schema 做请求验证(替代 express-validator)
  3. 使用 Fastify 的错误处理机制
  4. 保持路由结构一致
  5. 使用 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 代码]

要求:

  1. 处理 print 语句 → print 函数
  2. 处理 unicode/str 差异
  3. 处理 dict.keys()/values()/items() 返回类型变化
  4. 处理 integer division 差异
  5. 使用 Python 3 的新特性(f-string、type hints、pathlib 等)
  6. 标注需要特别注意的兼容性问题

### 常见迁移点

```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. 迁移代码到 [目标技术]
  2. 迁移测试到 [目标测试框架]
  3. 确保测试覆盖率不降低
  4. 如果迁移引入了新的边界情况,添加新的测试

---

## 批量迁移技巧

### 1. 先迁移类型定义

请分析以下项目的代码,提取所有需要定义的 TypeScript 类型。 只输出类型定义文件(.d.ts),不要迁移实际代码。

文件列表: [文件列表和关键代码片段]


### 2. 从叶子节点开始

请分析以下项目的依赖关系,给出迁移顺序建议。 原则:先迁移没有内部依赖的模块(叶子节点),再迁移依赖它们的模块。

模块列表: [模块列表和依赖关系]


### 3. 迁移检查清单

每个文件迁移后,用这个提示词做检查:

请检查以下迁移是否正确。

原始代码([源技术]): [原始代码]

迁移后代码([目标技术]): [迁移后代码]

请检查:

  1. 功能是否完全一致
  2. 是否遗漏了边界情况处理
  3. 是否使用了目标技术的最佳实践
  4. 是否有类型安全问题
  5. 是否有性能差异

---

## 总结

| 迁移场景 | 难度 | AI 辅助价值 |
|---------|------|-----------|
| JS → TS | 中 | 高(类型推断是 AI 强项) |
| React Class → Hooks | 中 | 高(模式转换很机械) |
| Vue 2 → Vue 3 | 中 | 高(API 映射明确) |
| Express → Fastify | 低 | 中(差异不大) |
| Python 2 → 3 | 低 | 中(大部分是语法变化) |
| 跨语言迁移 | 高 | 中(需要人工验证逻辑) |

AI 能帮你完成 70-80% 的机械性迁移工作,但剩下的 20-30%——业务逻辑验证、边界情况处理、性能测试——仍然需要人工把关。

> 代码迁移就像搬家:AI 帮你打包和搬运,但哪些东西该扔、哪些该留、新家怎么布置,还是得你自己决定。

评论

加载中...

相关文章

分享:

评论

加载中...