TypeScript 真的是 JavaScript 的"平替"吗?5 个真实项目踩坑记录

TypeScript 真的是 JavaScript 的"平替"吗?5 个真实项目踩坑记录

先给结论:TypeScript 不是 JavaScript 的平替,而是 JavaScript 在"生产级项目"上的上层约束层 。它编译后跑的还是 JS,运行时性能完全一致,但它把一部分本该在凌晨 3 点由 Sentry 抓的 bug,提前到了 tsc 和编辑器里。

下面用 5 个真实项目场景的踩坑记录,讲清楚它"补了什么"也"漏了什么"。


坑 1:Node 服务迁移 TS 后,类型过了,线上照样崩

场景 :老 Express 项目迁 TS,把 req.body 标成 interface UserBody { age: number },顺手删掉了原来的 typeof req.body.age === 'number' 校验。

踩坑:

客户端传 age: "twenty" 或干脆不传,TS 编译期完全不报;Express 收到的还是裸 JSON,运行时直接把字符串当数字累加,或下游 toFixed 炸掉。

教训:

TypeScript 的类型在编译后会被擦除,它不验证 HTTP、不验证 localStorage、不验证第三方接口响应。边界入口必须用 Zod / Valibot 做运行时校验,as 断言不是校验。

ini 复制代码
const UserBody = z.object({ age: z.number().int() });
const body = UserBody.parse(req.body); // 绿 tsc ≠ 安全运行时

坑 2:any 和 as 泛滥,TS 变成"纸安全带"

场景 :前端接一个字段天天变的 AI 接口,为了不让编译器叫,全员 const data: any = JSON.parse(raw),或者 return resp.json() as UserProfile。

踩坑:

上游悄悄把 commonName 改成 common_name,TS 一声不吭,组件里 user.commonName 编译通过,运行时拿到 undefined,列表页白屏。

教训:

  • any 一出现,类型病毒式传播,比纯 JS 还危险------因为给人"我已经类型安全了"的错觉。
  • 原型期用 unknown + 收窄,或先用 Zod schema 兜住,等接口稳定再反推类型。
  • ESLint 里 @typescript-eslint/no-explicit-any 和禁掉滥用 as 应尽早开。

坑 3:老 JS 项目"渐进迁移",allowJs 开了一年等于没迁

场景 :10 万行 JS 老仓库,按教程开 allowJs: true, strict: false,文件一个个改 .ts。

踩坑:

  • 前 3 个月只改了工具函数,业务文件全是 any 隐式推导;
  • 新人以为"项目是 TS 了"就放心改,结果 strictNullChecks 没开,user.name.toUpperCase() 在 user 为 null 时依旧线上崩;
  • 重构时编译器没拦住,因为一半代码根本没进类型检查。

教训:

渐进迁移的终点必须是 strict: true。建议路线:

  1. allowJs 共存 → 2. 改 .ts 时顺手开 noImplicitAny → 3. 按目录开 strictNullChecks → 4. 全量 strict。
    不走到 strict,迁移就是 theater(表演)。

坑 4:ERP 前端生产构建 66 个 TS 错误,全是"类型漂移"

场景 :React + Redux 前端迭代两年,中间改过领域模型:status → employmentStatus、phone → phoneNumber。

踩坑:

生产 tsc 一次性爆出 66 个错:

  • 旧组件还在读 user.status
  • 测试里 mock 的 Redux state 缺了后来加的 3 个 slice
  • React Router v6 的 Outlet 改造后旧测试用例类型对不上

正面价值:

这 66 个错误恰恰是 TS 的功劳------换 JS 版本项目,这些全是"点进去某页面控制台红一片"才发现。踩坑点在于类型没当成活文档维护 :接口改名要用 IDE 的 F2 rename 全量改,不要手动 find-replace;测试 mock 要用 DeepPartial<RootState> 工厂函数,别手写裸对象。


坑 5:小脚本和落地页强行上 TS,tsconfig 比业务代码长

场景:运营要一个 300 行的 Cloudflare Worker 转发脚本,leader 说"统一都用 TS"。

踩坑:

  • 配 tsconfig、装 @types/*、接 CI 的 tsc --noEmit,花半天;
  • 需求两周后废弃,类型投资全沉没;
  • 对比同规模纯 JS 文件,node script.js 直接跑,省掉整个构建心智。

教训:

TS 的盈亏平衡点大概在 单人维护超过 3 周 / 代码超 500--1000 行 / 贡献者 ≥ 2。低于这条线,JS + JSDoc 足够;高于这条线,TS 的重构安全感和入员 onboarding 收益才覆盖得了配置成本。


回到开头:是不是平替?

维度 JavaScript TypeScript
运行时表现 原生 编译成 JS,零差异
抓 bug 时机 运行时(常是生产) 编辑/编译期
重构 1 个字段改 47 处 grep+祈祷 编译器给清单
外部输入校验 自己写 仍要自己写(Zod 等)
小脚本/落地页 合适 过度配置
3 人+维护半年以上 维护税滚雪球 回本

所以更准确的说法是:

  • JS 是执行层事实标准,TS 是开发期契约层;
  • TS 替代不了 JS,因为它"运行不了";JS 也替代不了 TS 在中型以上团队里的可维护性收益。
  • 叫它"平替"会把人带偏------TS 是给 JS 项目买的编译期保险,不是换一辆车,是给同一辆车加装仪表盘和车道偏离预警,但油门刹车还是原来那套。
相关推荐
mldong2 小时前
工作流引擎的委托代批:一张单,两个办理人
后端·架构
高频因子挖掘机2 小时前
量化回测为什么不能随便选前复权?从收益率计算到成交价格的三个误区
后端·github·api
高频因子挖掘机4 小时前
回测收益为什么可能不真实?从时间戳、数据可用性到未来函数检查
后端·github·api
行百里er12 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机13 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
孟健14 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
码事漫谈15 小时前
丢得静悄悄,谈一谈 Agent 的记忆是怎么没的
后端
迪飞特科技15 小时前
智慧物业平台实战:Spring Boot 整合小程序实现报修巡检费用全流程
spring boot·后端·小程序
考虑考虑15 小时前
@JsonInclude注解使用
spring boot·后端·spring
IT_陈寒15 小时前
Vite的这个问题坑了我三天,原来如此解决!
前端·人工智能·后端