关于 allowjs-mixing
面向将现有 JavaScript 项目逐步迁移至 TypeScript 的团队。指南说明如何通过 `allowJs` 在代码库中混用 `.js` 和 `.ts` 文件,并逐步转换模块。
主要功能
- 01启用 JavaScript 与 TypeScript 混合文件
- 02逐步转换模块
- 03从依赖图的叶子模块开始
- 04在 JavaScript 与 TypeScript 间导入
- 05使用 JSDoc 为 JavaScript 添加类型
适用场景
- 01迁移大型 JavaScript 代码库
- 02不进行整体重写而采用 TypeScript
- 03迁移期间持续开发功能
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ marius-townhouse/ effective-typescript-skills --skill allowjs-mixing安装后在 Claude Code 中输入/allowjs-mixing确认已加载。
详细介绍
使用 allowJs 混合 TypeScript 和 JavaScript
概述
将大型 JavaScript 代码库迁移到 TypeScript,不必一次性全部完成。allowJs 编译器选项允许你在同一个项目中混合使用 .ts 和 .js 文件,从而逐步采用 TypeScript。这样可以增量迁移,让团队一次转换一个文件,同时保持代码库可正常运行。
对于无法进行大规模重写的大型迁移,这种方法至关重要。
何时使用此技能
- 将 JavaScript 项目迁移到 TypeScript
- 在 JS 代码库中逐步采用 TypeScript
- 在由 TypeScript 和 JavaScript 开发者组成的团队中协作
- 转换大型现有项目
- 团队仍在学习 TypeScript
铁律
使用 allowJs 启用增量迁移。按模块逐步转换文件,从叶子模块开始,沿依赖关系图向上推进。
检测
留意迁移过程中遇到的挑战:
// Can't migrate because:
- 1000+ JavaScript files
- Team still learning TypeScript
- Can't stop feature development
- Risk of breaking changes
启用 allowJs
// tsconfig.json
{
"compilerOptions": {
"allowJs": true, // Allow JavaScript files
"checkJs": false, // Don't type check JS (optional)
"outDir": "./dist",
"strict": true
},
"include": ["src/**/*"]
}
迁移策略
Phase 1: Enable allowJs
- Add tsconfig.json with allowJs: true
- Rename one file to .ts as proof of concept
- Ensure build still works
Phase 2: Convert leaf modules
- Start with files that have no dependencies
- Utilities, helpers, constants
- Low risk, easy wins
Phase 3: Work up dependency graph
- Convert files that only depend on converted files
- Gradually move toward entry points
Phase 4: Convert entry points last
- Main files, app entry points
- Most complex, most dependencies
转换文件
// utils.js (before)
export function formatDate(date) {
return date.toISOString().split('T')[0];
}
export const PI = 3.14159;
// utils.ts (after)
export function formatDate(date: Date): string {
return date.toISOString().split('T')[0];
}
export const PI = 3.14159;
在 JS 和 TS 之间导入
// app.ts - TypeScript importing JavaScript
import { formatDate } from './utils.js'; // .js extension
// TypeScript trusts the JS (with checkJs: false)
// With types for JS module
declare module './utils.js' {
export function formatDate(date: Date): string;
export const PI: number;
}
// legacy.js - JavaScript importing TypeScript
import { User } from './types.ts'; // Works with allowJs
// JS doesn't get type checking, but can import TS
为 JavaScript 添加类型
// @ts-check - Enable type checking for this file
/**
* @param {string} name
* @param {number} age
* @returns {string}
*/
function greet(name, age) {
return `Hello ${name}, you are ${age}`;
}
/** @type {string[]} */
const names = ['Alice', 'Bob'];
/** @typedef {{ x: number, y: number }} Point */
迁移检查清单
// 1. Set up tsconfig.json with allowJs
{
"compilerOptions": {
"allowJs": true,
"checkJs": false, // Enable later for stricter checking
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
}
// 2. Start with simple files
// - No dependencies
// - Pure functions
// - Well-tested
// 3. Add types gradually
// - Start with any if needed
// - Refine over time
// 4. Enable strict mode checks incrementally
// - noImplicitAny
// - strictNullChecks
// - strictFunctionTypes
抗压原则
迁移时:
- 先启用 allowJs:确保基础设施正常运行
- 从小处着手:转换一个文件,并确保构建正常
- 优先处理叶子模块:依赖越少,越容易处理
- 起初使用 any:之后可以进一步完善类型
- 跟踪进度:庆祝每一次小小的进展
危险信号
| 反模式 | 问题 | 解决方案 |
|---|---|---|
| 一次性全部重写 | 风险太高,耗时太长 | 使用 allowJs 增量迁移 |
| 首先转换入口点 | 依赖过多 | 从叶子模块开始 |
| 没有 tsconfig.json | 无法控制编译 | 正确设置 |
| 中途放弃 | 浪费精力 | 跟踪并庆祝进展 |
常见借口
“我们需要一次性转换所有内容”
事实:对于大型代码库,使用 allowJs 增量迁移更安全、更实用。
“混合使用 JS 和 TS 会让人困惑”
事实:这只是暂时的,而且易于管理。清晰的迁移计划能让一切井然有序。
“我们就继续用 JS 吧”
事实:TypeScript 的优势会随时间不断累积。从小处着手,逐步扩展。
快速参考
| 步骤 | 操作 | 时间安排 |
|---|---|---|
| 1 | 添加启用 allowJs 的 tsconfig | 第 1 天 |
| 2 | 转换 1-2 个工具文件 | 第 1 周 |
| 3 | 转换叶子模块 | 第 2-4 周 |
| 4 | 沿依赖关系图向上推进 | 第 1-3 个月 |
| 5 | 转换入口点 | 第 3-6 个月 |
| 6 | 移除 allowJs(可选) | 完成时 |
总结
使用 allowJs 逐步采用 TypeScript。从叶子模块开始,逐步转换文件。这样可以在不停止开发的情况下,让大型迁移变得可控。
参考资料
- Dan Vanderkam 著《Effective TypeScript》第 2 版
- 条目 81:使用 allowJs 混合 TypeScript 和 JavaScript
评论
支持 Markdown