讲解
把一个 JavaScript 项目迁移到 TypeScript,官方推荐的路线是渐进的四步。第一步:接入编译——把 tsc 加进构建,allowJs: true 让 .js 文件也被纳管,checkJs: false 先不检查它们,此时 TypeScript 只负责「看着」。第二步:逐个文件改后缀 .js → .ts,修显式报错;文件多的话按目录推进,每批可独立合并。第三步:提高严格度——从 strict: false 起步,按 strictNullChecks 最后开的顺序逐项打开(空值错误最多,留到基础设施就绪后)。第四步:消灭逃生舱——扫描 any、as unknown、@ts-ignore,制定新增代码零容忍规则。
两个加速工具:一是 JSDoc + checkJs——不改后缀,在 .js 文件里写 JSDoc 类型注释并开 checkJs,就能先享受检查(老项目、脚本目录很合适);二是 @ts-expect-error 注释——压制下一行错误,但如果错误消失它会自己报错(比 @ts-ignore 好,不会烂在代码里)。
最后是全教程的浓缩清单。要:开启 strict;能推断就不标注,参数与返回值除外;对象契约用 interface,其余用 type;外部数据入口做运行时校验(守卫或 zod);import type 表达纯类型依赖。不要:不用 any 消红;不写 as unknown as;不让类型体操进入业务代码;不在构造函数里依赖多态;不为「以后可能用到」提前抽象泛型。类型系统是工具,目标是让代码更敢说真话——而不是更复杂。
示例
JSDoc + checkJs:不改后缀先获得检查(js 块会以 --allowJs --checkJs 编译验证):
// @ts-check
/**
* @param {number} price
* @param {number} count
* @returns {number}
*/
function total(price, count) {
return price * count;
}
console.log(total(39, 2));
// total("39", 2); // 若取消注释:checkJs 会报 string 不能赋给 number
@ts-expect-error:压制已知错误,错误消失时自动报警:
// @ts-expect-error — 演示:故意把 number 赋给 string,这行错误被压制
const wrong: string = 123;
const right: string = "123";
console.log(typeof wrong, right);
一份收尾用的「迁移期」tsconfig(先松后紧的中间态):
{
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"moduleResolution": "bundler",
"allowJs": true,
"checkJs": false,
"strict": false,
"noImplicitAny": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src"]
}
常见坑
- 一次性全量改写:迁移期新旧混跑是常态,按目录小步合并,每步保持 CI 绿。
- 把 @ts-ignore 当橡皮泥:它不验证「错误还在不在」,优先 @ts-expect-error;两者都要带原因注释。
- 迁移完成度以报错为零衡量:真正的终点是新增代码不引入 any/as——配 lint 规则(no-explicit-any)守住增量。
- JSDoc 与 .ts 混用漂移:同一对象两处描述迟早不一致,JSDoc 是过渡手段,最终归一到 .ts。
小结
迁移四步:纳管 → 改后缀 → 提严格度 → 消灭逃生舱;checkJs 与 @ts-expect-error 是两个加速器;照清单守住日常。教程到此结束——接下来去真实项目里把类型写成团队的生产力。