一個四年歷史的項目,tsconfig.json里躺著"strict": false。你改成true,編輯器瞬間報出4300個錯誤。會議推遲,代碼回滾,一切照舊。
嚴格模式不是單一開關,而是8個獨立標志的打包組合。文檔把它當成二元選項呈現,結果讓原本一周能完成的遷移變成季度級僵局。實際上你可以逐個開啟,最便宜的幾乎零成本,最貴的藏著那4300個錯誤。按對順序來,每次PR小到評審員一杯咖啡就能看完。
![]()
以下是按遷移難度排序的八個標志,基于3萬行代碼庫的實測成本:
alwaysStrict:零成本熱身
這個標志給每個輸出文件加上"use strict",按嚴格模式解析源碼。對于近十年寫的代碼,成本基本為零——你早就不在用with語句,不給undefined賦值了,ES2015+的模塊默認就是嚴格模式。3萬行項目預計0-5個錯誤,都是老文件,反正后續重構也會動到。第一個開它,當作熱身。
noImplicitThis:箭頭函數的遺產清理
當函數內部的this沒有聲明類型、編譯器也無法推斷時報錯。修復方式是加一個this參數,運行時會被編譯掉。如果你的代碼庫用箭頭函數和類方法(2018年后寫的默認如此),這個問題很少出現。錯誤集中在事件處理器和老式原型代碼里。3萬行約5-30個錯誤,一個PR搞定。排第二。
strictBindCallApply:方法借用現原形
沒開這個標志時,bind、call、apply返回any,開了之后返回正確的函數類型。錯誤出現在借用方法的地方,比如Array.prototype.slice.call(arguments)。修復是加類型斷言或改寫成現代語法。3萬行約10-50個錯誤。排第三。
strictFunctionTypes:逆變參數的深水區
函數參數雙向協變是TypeScript早期為了兼容JavaScript做的妥協。這個標志關掉妥協,檢查函數參數類型的協變性。錯誤出現在回調函數、事件處理器、可選參數的處理上。3萬行約50-200個錯誤。需要分幾個PR,但每個改動都很局部。排第四。
noImplicitReturns:控制流的顯式化
函數所有代碼路徑必須返回指定類型。錯誤出現在提前返回或條件分支遺漏的情況。3萬行約30-100個錯誤。修復通常是補全返回語句或調整類型簽名。排第五。
noFallthroughCasesInSwitch:switch的窮舉檢查
禁止switch語句的case穿透,除非顯式注釋。錯誤數量取決于你寫多少switch。3萬行約20-80個錯誤。修復是加break或// fallthrough注釋。排第六。
strictPropertyInitialization:類屬性的初始化擔保
類屬性必須在聲明時或構造函數里初始化。錯誤出現在依賴外部初始化、延遲初始化、或者框架接管初始化的場景。3萬行約100-400個錯誤。需要區分是真正的bug還是合理的延遲初始化,用 definite assignment assertion(!)標記后者。排第七。
strictNullChecks:最后開的核武器
這是嚴格模式的分水嶺。關掉時,null和undefined可以賦值給任何類型;打開后,它們成為獨立的類型,必須顯式處理。這就是那4300個錯誤的來源。3萬行通常500-2000個錯誤,取決于代碼年齡和風格。
遷移策略:不要試圖一次修完。先開啟標志,把錯誤數量作為基線,然后按模塊或按錯誤類型分批修復。常見的修復模式包括:加可選鏈(?.)、空值合并(??)、非空斷言(!)、或者把類型收窄為T | null。每個PR控制在50-100個文件改動,保持可評審性。
strictNullChecks放在最后,不是因為最難,而是因為它的修復會和其他標志產生交互。先清理完其他七個標志的地雷,再面對這個,你會發現很多錯誤已經被前面的改動順帶解決了。
八個標志,八次PR,八次代碼評審,比一次4300個錯誤的爆炸更符合人類的工作節奏。嚴格模式的收益是漸進的,遷移也可以漸進。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.