经验分享:在团队中推行TypeScript五年,我们遇到了哪些坑?

阿乐
阿乐 管理员 黑卡会员
发布于 2026-09-11 14:40 ·2 浏览 ·0 回复

五年前,我们团队决定从 JavaScript 全面转向 TypeScript。当时大家的想法很朴素:类型能减少低级错误,重构更安心,代码即文档。五年过去,TypeScript 确实成了我们技术栈的基石,但这个过程远没有想象中顺利。今天不聊“TypeScript 有多好”,只复盘我们真实踩过的坑,以及后来怎么填的。

坑一:any 满天飞,类型系统形同虚设

推行初期,为了赶业务进度,很多人遇到类型报错第一反应就是 `any` 或 `@ts-ignore`。结果半年后统计,代码库里 `any` 的数量比业务组件还多。类型检查看似开了,实则被绕得干干净净。更麻烦的是,新人看到满地 `any`,以为这就是团队规范,跟着学。

后来我们做了三件事:第一,ESLint 加 `no-explicit-any` 规则,但先设为 warn,不阻塞 CI;第二,每周统计 `any` 新增数量,在周会上公示,形成正向压力;第三,把历史 `any` 按模块拆分,结合业务迭代逐步替换,而不是搞一次性“类型净化运动”。一年后,`any` 密度下降了七成,关键路径基本做到了类型闭环。

坑二:类型体操上瘾,代码变成谜题

有段时间,团队里几位类型爱好者开始卷“类型体操”:条件类型嵌套、递归泛型、模板字面量类型推导,一个函数签名能写三十行。作者很爽,但其他人 review 时直接懵了。有次一个工具类型报错,排查了一下午,最后发现是 `infer` 嵌套了四层。

我们后来定了一条朴素的原则:类型首先为业务服务,其次才是炫技。能用接口和联合类型说清楚的,不写条件类型;能用简单泛型表达的,不搞递归。类型代码也要像业务代码一样接受可读性审查。这条规则落地后,PR 讨论效率明显提升。

坑三:编译和构建速度拖垮开发体验

项目变大之后,`tsc --watch` 的冷启动和增量检查越来越慢,CI 里全量类型检查一度要跑十几分钟。开发改一行代码,等类型检查等到怀疑人生,有人干脆关掉编辑器提示。

我们做了几层优化:转译交给 esbuild/swc,类型检查独立跑 `tsc --noEmit`;开启 `incremental` 和 `tsBuildInfoFile`;把大项目拆成多个子项目,用 project references 管理依赖;CI 里类型检查和单测并行。最终本地类型反馈控制在两秒内,CI 也压到了三分钟以内。经验就是:不要让 tsc 既做转译又做检查,它两件事都不算快。

坑四:第三方类型定义参差不齐

@types 包版本滞后、库自带类型写错、多个声明文件冲突,这些问题几乎每个 TS 团队都遇到过。我们踩过最典型的一次,是某个库的类型定义把可选参数写成了必填,导致编译通过但运行时炸了。

应对策略是:优先选自带类型且维护活跃的库;对关键依赖锁定版本,升级前先看类型变更;确实有问题的,用本地 `d.ts` 打补丁,并记录在案。另外,我们开始用 `zod` 做运行时校验,把“类型正确”和“数据正确”分开处理——TypeScript 只保证编译期,接口返回什么,还得靠运行时兜底。

坑五:严格模式一刀切,团队士气受挫

有段时间我们想一步到位开 `strict`,结果一开,上千个报错扑面而来。大家每天被红色波浪线包围,改到后面纯粹为了消错而写类型,甚至开始反感 TypeScript。

后来改成渐进式:先开 `noImplicitAny`,再开 `strictNullChecks`,按模块迁移,允许暂时用 `// @ts-expect-error` 并注明原因和到期时间。同时配套内部分享和 CR 指南,把常见类型写法沉淀成文档。半年后全量开启 strict,反而没什么人抱怨了。

五年下来,TypeScript 带给我们的收益远大于成本,但推行它从来不是纯技术问题,而是组织问题。工具配置可以查文档,真正难的是统一认知、控制节奏、容忍渐进。如果你正在团队里推 TypeScript,不妨把预期放长一点:先定规范,再谈严格;先解决体验,再追求完美。坑总会踩,但别在同一个坑里躺五年。

本文转载自 阿乐技术社区,原文地址:https://www.leleweb.cn/thread-223.html
转载请注明出处,版权归原作者所有。

全部回复 0

还没有回复,来抢沙发~