话说回来,这个“退魔少女”项目,我一开始可不是想搞什么大动作。最初就是为了快速验证一个想法,随便拉了套原生JS的代码就硬着头皮写起来了。写着写着,功能倒是堆满了,但那个代码,用我自己的话说,就是一堆泥巴。所有变量都是动态的,数据结构全靠脑子记,一个月前写的代码,我自己都不敢碰。
最近我终于受不了了。上周一个线上Bug,调试了整整一天,发现就是一个对象属性名打错了,JavaScript屁都不吭一声,直接返回个undefined,整个页面就崩了。当时我就拍桌子了,必须动大手术,变身成TS退魔少女,用类型来彻底封印这些低级错误。
从泥巴到圣剑:TS化实录
我砸进去第一个周末,专门用来研究TS的配置文件(tsconfig)。光是决定模块化要用CommonJS还是ESM,以及严格模式开到什么程度,就让我挠头了半天。配置搞定,我立马开始了最核心的业务模块迁移。
我采取了由内而外的策略,先搞定数据层,再往上层应用走。这是实践中的重点,也是最痛苦的地方。
- 第一步:定义接口和类型别名。这是TS的灵魂。我把所有核心数据结构全部锁死,明确规定了哪些字段是必填,哪些是可选,类型是什么。以前代码里的注释全是废话,现在类型定义就是最好的文档。
- 第二步:处理遗留的第三方库。那些老旧的,没有自带类型定义的npm包,简直是噩梦。我只能自己去社区抠、去GitHub扒拉,找有没有人贡献的类型声明文件(*)。实在没有,我只能硬着头皮自己写声明文件,让TS编译器能认得这些老家伙。
- 第三步:重构状态管理和副作用处理。这是这回更新的重中之重。以前状态变化依赖全局变量,那叫一个乱。现在我强制加上了严格的输入输出类型校验,尤其是对于异步操作返回的Promise,必须明确其成功和失败的类型。
你别看这三步说得轻松,中间我差点把鼠标都砸了。最让我崩溃的是处理老模块里的那个日期工具函数。我反复给它定义输入输出类型,但TS总是报错说类型不兼容,来来回回折腾了六七个小时,发现是项目依赖的一个底层工具包版本太老,它导出的类型结构跟TS最新的严格模式有冲突。我当时就想,这哪里是退魔少女,这是在驱逐我自己的魔障!
不过现在好了。代码结构清晰了,每动一行代码,心里都有底。类型就像一把圣剑,帮我在编译期就斩断了九成的Bug。任何尝试传入错误数据的行为,都会被TS这个“退魔少女”在第一时间拦截并大声喊出来。这感觉,就像手里握着一把真家伙,而不是以前那个随时会断的木棍。后续再有更新,就轻松多了。大家如果也在JS的泥潭里挣扎,听我一句劝,赶紧变身!