做者:Paul Cowan翻譯:瘋狂的技術宅javascript
原文:https://blog.logrocket.com/is...前端
未經容許嚴禁轉載java
在開始以前,但願你們知道,我是 TypeScript 愛好者。它是我在前端 React 項目和基於後端 Node 工做時的主要編程語言。但我確實有一些疑惑,因此想在本文中進行討論。迄今爲止,我已經用 TypeScript 寫了至少三年的代碼,因此 TypeScript 作得的確不錯,並且知足了個人需求。ios
TypeScript 克服了一些很難解決的問題,併成爲前端編程領域的主流。 TypeScript 在這篇列出了最受歡迎的編程語言的文章中排名第七位。git
不管是否使用 TypeScript,任何規模的開發團隊都應該遵循如下慣例:程序員
TypeScript 能夠在這些基礎之上增長額外的安全性,但我認爲這在編程語言需求列表中應該排在後面。github
我認爲這多是 TypeScript 當前版本的主要問題,可是首先讓我定義 健全 和 非健全 的類型系統。面試
健全的類型系統是可以確保你的程序不會進入無效狀態的系統。例如,若是表達式中的靜態類型爲 string
,則在運行時,要保證在評估它時僅得到 string
。typescript
在健全的類型系統中,絕對不會在編譯時或運行時產生表達式與預期類型不匹配的狀況。編程
固然 TypeScript 有必定程度的健全性,並捕獲如下類型錯誤:
// 'string' 類型不可分配給 'number' 類型 const increment = (i: number): number => { return i + "1"; } // Argument of type '"98765432"' is not assignable to parameter of type . // 沒法將參數類型 '"98765432"' 分配給參數類型'number'。 const countdown: number = increment("98765432");
100% 的健全性不是 Typescript 的目標,這是在 non-goals of TypeScript 列表中第 3 條中明確指出的事實:
...適用健全或「證實正確的」類型的系統。相反,要在正確性和生產率之間取得平衡。
這意味着不能保證變量在運行時具備定義的類型。我能夠用下面的例子來講明這一點:
interface A { x: number; } let a: A = {x: 3} let b: {x: number | string} = a; b.x = "unsound"; let x: number = a.x; // 不健全的 a.x.toFixed(0); // 什麼鬼?
上面的代碼是 不健全 的,由於從接口 A
中可以知道 a.x
是一個數字。不幸的是,通過一系列從新分配後,它最終以字符串形式出現,而且如下代碼可以編譯經過,可是會在運行時出錯。
不幸的是,這裏顯示的表達式能夠正確編譯:
a.x.toFixed(0);
我認爲這多是 TypeScript 最大的問題,由於健全性不是目標。我仍然會遇到許多運行時錯誤,tsc
編譯器不會標記這些錯誤。經過這種方法,TypeScript 在健全和不健全的陣營中腳踏兩隻船。這種半途而廢的現象是經過 any
類型強制執行的,我將在後面提到。
我仍然須要編寫不少的測試,這讓我感到沮喪。當我第一次開始使用 TypeScript 時錯誤地得出結論:能夠沒必要編寫這麼多單元測試了。
TypeScript 挑戰了現狀,並聲稱下降使用類型的認知開銷比類型健全性更重要。
我可以理解爲何 TypesScript 會走這條路,而且有一個論點指出,若是健全類型系統可以獲得 100% 的保證,那麼對 TypeScript 的使用率講不會那麼高。這種觀點隨着 dart 語言的逐漸流行( Flutter 現已被普遍使用)被反駁了。健全性是 dart 語言的目標,這裏是相關的討論(https://dart.dev/guides/langu...)。
不健全以及 TypeScript 暴露在嚴格類型以外的各類轉義符使它的有效性大大下降,不過這總比沒有強一些。個人願望是,隨着 TypeScript 的流行,可以有更多的編譯器選項可供使用,從而使高級用戶能夠獲得 100% 的可靠性。
運行時類型檢查不是 TypeScript 的目標,所以這種願望可能永遠不會實現。例如在處理從 API 調用返回的 JSON 時,運行時類型檢查將是有好處的。若是能夠在類型級別上進行控制,則不須要那麼多的錯誤種類和單元測試。
正是由於沒法在運行時保證全部的事情,因此可能會發生:
const getFullName = async (): string => { const person: AxiosResponse = await api(); //response.name.fullName 可能會在運行時返回 undefined return response.name.fullName }
儘管有一些很棒的支持庫,例如 io-ts,但這可能意味着你必須複製本身的model。
any
類型和嚴格性選項any
類型就是這樣,編譯器容許任何操做或賦值。
TypeScript 在一些小細節上每每很好用,可是人們傾向於在 any
類型上花費不少時間。我最近在一個 Angular 項目中工做,看到不少這樣的代碼:
export class Person { public _id: any; public name: any; public icon: any;
TypeScript 讓你忘記類型系統。
你能夠用 any
強制轉換任何一種類型:
("oh my goodness" as any).ToFixed(1); // 還記得我說的健全性嗎?
strict
編譯器選項啓用瞭如下編譯器設置,這些設置會使事情聽起來更加合理:
--strictNullChecks
--noImplicitAny
--noImplicitThis
--alwaysStrict
還有 eslint 規則 @typescript-eslint/no-explicit-any。
any
的泛濫會破壞你類型的健全性。
必須重申,我是 TypeScript 愛好者,並且一直在平常工做中使用它,可是我確實認爲它出現的時間還很短,並且類型還並不徹底合理。 Airbnb 聲稱 TypeScript 能夠阻止 38% 的錯誤。我很是懷疑這個數字的準確性。 TypeScript 不會對現有的作法有良好的提升。我仍然必須編寫儘量多的測試。你可能會不一樣意,不過我一直在編寫更多的代碼,而且不得不去編寫類型測試,同時仍然會遇到意外的運行時錯誤。
TypeScript 提供了基本的類型檢查,但健全性和運行時類型檢查不是它的目標,這使 TypeScript 在美好的世界和咱們所處的現狀中採起折衷。
TypeScript 的亮點在於有良好的 IDE 支持,例如 vscode,若是咱們輸入了錯誤的內容,將會得到很好的視覺反饋。
vscode中的TypeScript錯誤
經過 TypeScript 還能夠加強重構的功能,而且在對修改後的代碼進行編譯時,能夠當即識別出代碼的改變(例如方法簽名的更改)。
TypeScript 啓用了良好的類型檢查,而且絕對要比沒有類型檢查或僅使用普通的 eslint 更好,可是我認爲它還能夠作更多的事情。對於那些想要更多的人來講,還可以提供足夠多的編譯器選項。