作者 | Robert Vitonsky
編譯 | 云中
幾天前,漢森 (David Heinemeier Hansson)宣布 Turbo8 即將放棄 TypeScript。我心想:放棄就放棄吧,反正我也不知道 Turbo 8 是什么鬼。
然而,在過(guò)去的幾年里,一些前端程序員試圖向我推銷(xiāo)“ TypeScript 沒(méi)用,只測(cè)著玩玩”的想法。我認(rèn)為,有這種觀點(diǎn)的人要么不關(guān)心代碼質(zhì)量,要么根本不知道 TypeScript 是什么。在這里,我將解釋為什么應(yīng)該使用 TypeScript。
注:本文作者 Vitonsky 是一名超過(guò)10年的有著復(fù)雜項(xiàng)目的前端大牛,參與了許多開(kāi)源項(xiàng)目的開(kāi)發(fā):比如翻譯網(wǎng)站的瀏覽器插件 Linguist、模塊 UI 工具ElegantUI、翻譯 DOM 節(jié)點(diǎn)的 DomTranslator 庫(kù)等等。
1、代碼質(zhì)量控制的“好手”
代碼質(zhì)量控制是一個(gè)保持代碼可維護(hù)性的復(fù)雜過(guò)程。你不能僅僅用 100% 的測(cè)試覆蓋代碼,或者審查每個(gè)拉取請(qǐng)求并確保你的代碼是可維護(hù)的,還應(yīng)該讓除你之外的其他人也可以識(shí)別并搞定它。
根本無(wú)法保證自己的代碼沒(méi)有 bug 的同時(shí)具有完美的可維護(hù)性。你只能在存儲(chǔ)庫(kù)中增加防御結(jié)構(gòu),以使其難以推送帶有錯(cuò)誤的“炸彈”代碼。阻止“炸彈”代碼的障礙越多,代碼質(zhì)量就越好。
這意味著你應(yīng)該一起使用所有方法來(lái)保護(hù)存儲(chǔ)庫(kù)中的代碼:?jiǎn)卧?e2e/集成測(cè)試、代碼審查、代碼分析工具以及維護(hù)清晰的文檔等。
TypeScript 是一個(gè)強(qiáng)大的代碼分析工具;它可以檢測(cè)代碼中的許多缺陷。TypeScript 編譯器迫使程序員確保代碼在類(lèi)型級(jí)別上是正確的。David 和許多其他人低估了靜態(tài)類(lèi)型的價(jià)值。
讓我們看看 TypeScript 為代碼質(zhì)量帶來(lái)了哪些好處。
2、contract 對(duì)代碼的重要性
靜態(tài)類(lèi)型允許在代碼中定義 contract。
type Participant = {
id: string;
name: string;
};
function sayHi(participant: Participant) {
//...
console.log(`Hi ${participant.name}`);
}
該 sayHi 函數(shù)需要一個(gè)具有精確屬性和精確類(lèi)型的對(duì)象,并且它不關(guān)心該函數(shù)的用戶(hù)將做什么來(lái)滿(mǎn)足要求。編譯器確保類(lèi)型正確。
用戶(hù)可能會(huì)提供一個(gè)不符合要求的對(duì)象并將類(lèi)型強(qiáng)制轉(zhuǎn)換為 any,但這不是函數(shù) sayHi 的問(wèn)題。這是一種責(zé)任委托,是開(kāi)發(fā)人員必須理解的一個(gè)重要概念,才能正確使用 TypeScript 并獲得其好處。
程序員必須驗(yàn)證任何不受信任的數(shù)據(jù),例如用戶(hù)輸入和其他 IO 數(shù)據(jù),或與 JavaScript 互操作的結(jié)果。驗(yàn)證和設(shè)置類(lèi)型后,他們可以將數(shù)據(jù)傳遞給 TypeScript 代碼,并相信合同將得到遵守,因?yàn)?TypeScript 編譯器已經(jīng)檢查了代碼。如果程序員強(qiáng)制轉(zhuǎn)換類(lèi)型,他們必須確保代碼在運(yùn)行時(shí)正確。
如果你將項(xiàng)目中的非相交類(lèi)型轉(zhuǎn)換為任何非 unknown 的類(lèi)型(沒(méi)有運(yùn)行時(shí)驗(yàn)證),那么代碼質(zhì)量可能存在問(wèn)題。
contract 可以避免為每個(gè)函數(shù)編寫(xiě)驗(yàn)證以確保數(shù)據(jù)正確。這對(duì)于性能和代碼整潔度來(lái)說(shuō)都很好,代碼變得愚蠢而簡(jiǎn)單。
3、使用JS造成的不好經(jīng)驗(yàn)和成本
有時(shí)我會(huì)用純 JavaScript 編寫(xiě)代碼,主要是在瀏覽器控制臺(tái)中,以便在網(wǎng)頁(yè)上進(jìn)行快速計(jì)算或數(shù)據(jù)解析。幾個(gè)月前,我為 Node.js 編寫(xiě)了一個(gè)使用 ChatGPT 翻譯區(qū)域設(shè)置文件的腳本。這些文件包含長(zhǎng)文本,而 ChatGPT 有限制,因此需要一些時(shí)間對(duì)文本進(jìn)行切片、翻譯、在ChatGPT的結(jié)果中查找錯(cuò)誤、根據(jù)需要重新翻譯,然后將切片重新連接在一起。根據(jù)區(qū)域設(shè)置文件的大小,此過(guò)程大約需要 3-5 分鐘。
在這個(gè)過(guò)程中,由于一些瑣碎的類(lèi)型錯(cuò)誤,我浪費(fèi)了一些時(shí)間,比如忘記使用 wait,這導(dǎo)致一個(gè)變量包含 Promise,并將“[object Promise]”寫(xiě)入文件而不是翻譯文本,或者將錯(cuò)誤的對(duì)象作為函數(shù)參數(shù)提供。
TypeScript 消除了這樣的錯(cuò)誤。
4、 TS更面向未來(lái)
TypeScript 為你的代碼提供了其他工具分析的潛力,因?yàn)樗砑恿松舷挛摹?/p>
使用 IDE,你可以重命名接口中的屬性,并且實(shí)現(xiàn)該接口的所有實(shí)體將自動(dòng)在各自的位置更新屬性的名稱(chēng)。
ChatGPT 和 Copilot 等 AI 工具受益于 TypeScript 提供的附加元信息,有可能改進(jìn)代碼分析和代碼生成。這些分析工具可以更好地識(shí)別潛在風(fēng)險(xiǎn)的代碼。
靜態(tài)類(lèi)型和測(cè)試相得益彰。前端代碼是高度異步的,這使得覆蓋所有可能的測(cè)試用例并考慮所有潛在的代碼狀態(tài),變得非常有挑戰(zhàn)性。TypeScript 迫使程序員處理一個(gè)狀態(tài)可能具有的所有可能情況,從而增強(qiáng)代碼可靠性。
5、類(lèi)型:復(fù)雜性與質(zhì)量的取舍
漢森還說(shuō)道說(shuō):
“TypeScript 對(duì)我來(lái)說(shuō)只是阻礙。不僅因?yàn)樗枰@式的編譯步驟,還因?yàn)樗谩?lèi)型體操’污染了代碼,這給我的開(kāi)發(fā)體驗(yàn)增添了很少的樂(lè)趣,而且常常帶來(lái)相當(dāng)大的悲傷。應(yīng)該容易的事情變得困難,而困難的事情變成了‘a(chǎn)ny’。所以不用了,謝謝!”
確實(shí),有時(shí)必須編寫(xiě)重要的類(lèi)型,才能讓編譯器相信你的數(shù)據(jù)是正確的。但事實(shí)就是這樣:創(chuàng)建高質(zhì)量的可維護(hù)代碼通常需要付出艱苦的努力。
6、結(jié)論:會(huì)用的人不會(huì)抱怨工具
TypeScript 只是一個(gè)工具,如果你簡(jiǎn)單地啟用它,它不會(huì)自動(dòng)提高代碼質(zhì)量。你的項(xiàng)目必須制定正確使用該工具的規(guī)則,以及執(zhí)行這些規(guī)則的架構(gòu)師。規(guī)則越嚴(yán)格越好。
當(dāng)在項(xiàng)目中禁用靜態(tài)類(lèi)型時(shí),你將失去許多控制代碼質(zhì)量的功能。
JS 文檔和 .d.ts 類(lèi)型聲明文件無(wú)法替代代碼的靜態(tài)類(lèi)型。它們只是聲明實(shí)體外部 API 的方法,但不允許分析實(shí)體內(nèi)的代碼(函數(shù)、類(lèi)和其他代碼塊)。
原文鏈接:https://vitonsky.net/blog/2023/09/08/typescript-and-code-quality/