摘要:怎么影響了我的思考方式對前端開發者來說,能強化了面向接口編程這一理念。使用的過程就是在加深理解的過程,確實面向接口編程天然和靜態類型更為親密。
電影《降臨》中有一個觀點,語言會影響人的思維方式,對于前端工程師來說,使用 typescript 開發無疑就是在嘗試換一種思維方式做事情。
其實直到最近,我才開始系統的學習 typescript ,前后大概花了一個月左右的時間。在這之前,我也在一些項目中模仿他人的寫法用過 TS,不過平心而論,在這一輪系統的學習之前,我并不理解 TS。一個多月前,我理解的 TS 是一種可以對類型進行約束的工具,但是現在才發現 TS 并不簡單是一個工具,使用它,會影響我寫代碼時的思考方式。
TS 怎么影響了我的思考方式對前端開發者來說,TS 能強化了「面向接口編程」這一理念。我們知道稍微復雜一點的程序都離不開不同模塊間的配合,不同模塊的功能理應是更為清晰的,TS 能幫我們梳理清不同的接口。
明確的模塊抽象過程TS 對我的思考方式的影響之一在于,我現在會把考慮抽象和拓展看作寫一個模塊前的必備環節了。當然一個好的開發者用任何語言寫程序,考慮抽象和拓展都會是一個必備環節,不過如果你在日常生活中使用過清單,你就會明白 TS 通過接口將這種抽象明確為具體的內容的意義所在了,任何沒有被明確的內容,其實都有點像是可選的內容,往往就容易被忽略。
舉例來說,比如說我們用 TS 定義一個函數,TS 會要求我們對函數的參數及返回值有一個明確的定義,簡單的定義一些類型,卻能幫助我們定位函數的作用,比如說我們設置其返回值類型為 void ,就明確的表明了我們想利用這個函數的副作用;
把抽象明確下來,對后續代碼的修改也非常有意義,我們不用再擔心忘記了之前是怎么構想的呢,對多人協作的團隊來說,這一點也許更為重要。
當然使用 jsdoc 等工具也能把對函數的抽象明確下來,不過并沒有那么強制,所以效果不一定會很好,不過 jsdoc 反而可以做為 TS 的一種補充。更自信的寫代碼
TS 還能讓我更自信的寫前端代碼,這種自信來自 TS 可以幫我們避免很多可能由于自己的忽略造成的 bug。實際上,關于 TS 輔助避免 bug 方面存在專門的研究,一篇名為To Type or Not to Type: Quantifying Detectable Bugs in JavaScript 的論文,表明使用 TS 進行靜態類型檢查能幫我們至少減少 15% 以上的 bug (這篇論文的研究過程也很有意思,感興趣可以點擊鏈接閱讀)。
可以舉一個例子來說明,TS 是怎么給我帶來這種自信的。
下面這條語句,大家都很熟悉,是 DOM 提供依據 id 獲取元素的方法。
const a = document.getElementById("a")
對我自己來說,使用 TS 之前,我忽略了document.getElementById的返回值還可能是 null,這種不經意的忽略也許在未來就會造成一個意想不到的 bug。
使用 TS,在編輯器中就會明確的提醒我們 a 的值可能為 null。
我們并不一定要處理值 null 的情況,使用 const a = document.getElementById(‘id")! 可以明確告訴 TS ,它不會是 null,不過至少,這時候我們清楚的知道自己想做什么。
使用 TS 的過程就是一種學習的過程使用 TS 后,感覺自己通過瀏覽器查文檔的時間明顯少了很多。無論是庫還是原生的 js 或者 nodejs,甚至是自己團隊其它成員定義的類型。結合 VSCode ,會有非常智能的提醒,也可以很方便看到相應的接口的確切定義。使用的過程就是在加深理解的過程,確實「面向接口編程」天然和靜態類型更為親密。
比如說,我們使用 Color 這個庫,VSCode 會有下面這類提醒:
不用去查文檔,我們就能看到其提供的 API。
如果我們去看這個庫的源文件會發現,能有提醒的原因在于存在下面這樣的定義:
// @types/color/index.d.TS interface Color { toString(): string; toJSON(): Color; string(places?: number): string; percenTString(places?: number): string; array(): number[]; object(): { alpha?: number } & { [key: string]: number }; unitArray(): number[]; unitObject(): { r: number, g: number, b: number, alpha?: number }; ... }
這種提醒無疑能增強開發的效率,雖然定義類型在早期會花費一定的時間,但是對于一個長期維護的比較大型的項目,使用 TS 非常值得。
一種學習 typescript 的路徑也許是因為,我之前從未系統的學習過一門靜態語言,所以從開始學到感覺自己基本入門了 TS 花的精力還挺多的。
學習 TS 的過程中,主要參考了以下這些資料,你可以直接點擊鏈接查看,也可以繼續看后文,我對這些資料有著一些簡單的分析。
TypeScript handbook — book
TypeScript Deep Dive — book
TypeScript-React-Starter — github
react-typescript-cheaTSheet — github
Advanced Static Types in TypeScript — egghead.io
Use TypeScript to develop React Applications — egghead.io
Practical Advanced TypeScript — egghead.io
Ultimate React Component Patterns with Typescript 2.8 — medium
The TypeScript Tax — medium
在閱讀上述資料的過程中,我使用 TS 重寫了一個基于 CRA 的簡單但是很完整的前端項目,現在覺得,使用 TS 來開發工作中的常見需求,應該都能應對了。如果你是剛剛開始學 TS,不妨參照下面的路徑學習。
搭建 TS 運行環境不要誤解,并非從零搭建。學習實踐性很強的內容時,邊學邊練習可以幫我們更快的掌握。如果你使用 React,借助 yarn 或者 create-react-app,可輕易的構造一個基于 TS 的項目。
在命令行中執行下述命令即可生產可直接使用的項目:
# 使用 yarn $ yarn create react-app TS-react-playground --typescript # 使用 npx $ npx create-react-app TS-react-playground --typescript
隨后如果需要,可以在tsconfig.json中添加額外的配置。
就我個人而言,我喜歡同步配置 TS-lint 與 prettier,已免去之后練習過程中格式的煩惱。配置方法可以參考 Configure TypeScript, TSLint, and Prettier in VS Code for React Native Development 這篇文章,或者看我的配置記錄。
如果你不使用 React,TypeScript 官方文檔首頁就提供了 TS 配合其它框架的使用方法。
理解關鍵的概念我一直覺得,學習一項新的技能,清楚其邊界很重要,相關的細節知識則可以在后續的使用過程中逐步的了解。我們都知道,TS 是 JS 的超集,所以學習 TS 的第一件事情就是要找到「超」的邊界在哪里。
這個階段,推薦閱讀 TypeScript handbook — book,這本書其實也是官方推薦的入門手冊。這里給的鏈接是中文翻譯版的鏈接,翻譯的質量非常好,雖然內容沒有英文官方文檔新,不過學習新的東西最好還是從自己最熟悉的內容入手,所以不妨先看中文文檔。閱讀過程中遇到的示例,都可以在上面搭建的 TS-playground 中練習一下,熟悉一下。
TS 做為 JS 的超集,其「超」其實主要在兩方面
TS 為 JS 引入了一套類型系統;
TS 支持一些非 ECMAScript 正式標準的語法,比如裝飾器;
關于第二點,TS 做的事情有些類似 babel,所以也有人說 TS 是 babel 最大的威脅。不過這些新語法,很可能你早就使用過,本文不再贅述。
比較難理解的其實是這套類型系統,這套類型系統有著自己的聲明空間(Declaration Spaces),具有自己的一些關鍵字和語法。
對我來說,學習 TS 最大的難點就在于這套類型系統中有著一些我之前很少了解的概念,在這里可以大致的梳理一下。
一些 TS 中的新概念編程實際上就是對數據進行操作和加工的過程。類型系統能輔助我們對數據進行更為準確的操作。TypeScript 的核心就在于其提供一套類型系統,讓我們對數據類型有所約束。約束有時候很簡單,有時候很抽象。
TS 支持的類型如下:boolean,number,string,[],Tuple,enum,any,void,null,undefined,never,Object。
TS 中更復雜的數據結構其實都是針對上述類型的組合,關于類型的基礎知識,推薦先閱讀基礎類型一節,這里只討論最初對我造成困擾的概念:
enum:
現在想想 enum ?枚舉類型非常實用,很多其它的語言都內置了這一類型,合理的使用枚舉,能讓我們的代碼可讀性更高,比如:
const enum MediaTypes { JSON = "application/json" } fetch("https://swapi.co/api/people/1/", { headers: { Accept: MediaTypes.JSON } }) .then((res) => res.json())
never:
never 代表代碼永遠不會執行到這里,常常可以應用在 switch case 的 default 中,防止我們遺漏 case 未處理,比如:
enum ShirTSize { XS, S, M, L, XL } function assertNever(value: never): never { console.log(Error(`Unexpected value "${value}"`)); } function prettyPrint(size: ShirTSize) { switch (size) { case ShirTSize.S: console.log("small"); case ShirTSize.M: return "medium"; case ShirTSize.L: return "large"; case ShirTSize.XL: return "extra large"; // case ShirTSize.XS: return "extra small"; default: return assertNever(size); } }
下面是上述代碼在我的編輯器中的截圖,編輯器會通過報錯告知我們還有未處理的情況。
類型斷言:
類型斷言其實就是你告訴編譯器,某個值具備某種類型。有兩種不同的方式可以添加類型斷言:
someValue as string
關于類型斷言,我看文檔時的疑惑點在于,我想不到什么情況下會使用它。后來發現,當你知道有這么一個功能,在實際使用過程中,就會發現能用得著,比如說遷移遺留項目時。
Generics(泛型):
泛型讓我們的數據結構更為抽象可復用,因為這種抽象,也讓它有時候不是那么好理解。泛型的應用場景非常廣泛,比如:
type Nullable= { [P in keyof T]: T[P] | null; };
能夠讓某一種接口的子類型都可以為 null。我記得我第一次看到泛型時也覺得它很不好理解,不過后來多用了幾次后,就覺得還好了。
interface 和 type
interface 和 type 都可以用來定義一些復雜的類型結構,最很多情況下是通用的,最初我一直沒能理解它們二者之間區別在哪里,后來發現,二者的區別在于:
* `interface`創建了一種新的類型,而 type 僅僅是別名,是一種引用; * `type` 不能被 `extends` 和 `implements`
在視頻 Use Types vs. Interfaces from @volkeron on @eggheadio 中,通過實例對二者的區別有更細致的說明。
類型保護
TS 編譯器會分析我們的程序并為某一個變量在指定的作用域來指明盡可能確切的類型,類型保護就是一種輔助確定類型的方法,下面的語句都可以用作類型保護:
* `typeof padding === "number"` * `padder instanceof SpaceRepeatingPadder`
一個應用實例是結合 redux 中的 reducer 中依據不同的 type,TS 能分別出不同作用域內 action 應有的類型。
類型映射
類型映射是 TypeScript 提供的從舊類型中創建新類型的一種方式。它們非常實用。比如說,我們想要快速讓某個接口中的所有屬性變為可選的,可以按照下面這樣寫:
interface Person { name: string; age: number; } type PartialPerson = { [P in keyof Person]?: Person[P] }
還有一個概念叫做 映射類型,TS 內置一些映射類型(實際上是一些語法糖),讓我們可以方便的進行類型映射。比如通過內置的映射類型 Partial ,上面的表達式可以按照下面這樣寫:
interface Person { name: string; age: number; } type PartialPerson = Partial
常見的映射類型,可以參看這篇文章 — TS 一些工具泛型的使用及其實現,除了做為語法糖內置在 TS 中的映射類型(如Readonly),這篇文章中也提到了一些未內置最 TS 中但是很實用的映射類型(比如 Omit)。
第三方的庫,如何得到類型支持
我們很難保證,第三方的庫都原生支持 TS 類型,在你使用過一段時間 TS 后,你肯定安裝過類似 @types/xxx 的類型庫,安裝類似這樣的庫,實際上就安裝了某個庫的描述文件,對于這些第三方庫的類型的定義,都存儲在DefinitelyTyped 這個倉庫中,常用的第三方庫在這里面都有定義了。在 TypeSearch 中可以搜索第三方庫的類型定義包。
關于類型,還有一些很多其它的知識點,不過一些沒有那么常用,一些沒有那么難理解,在此暫不贅述。
消化學到的新概念我首次看完《TypeScript handbook》時,確實覺得自己懂了不少,但是發現動手寫代碼,還是會經常卡住。追其原因,可能在于一下子接收了太多的新概念,一些概念并沒有來得及消化,這時候我推薦看下面這門網課:
Advanced Static Types in TypeScript — egghead.io
看視頻算是一種比較輕松的學習方式,這門課時長大概是一個小時。會把 TypeScript handbook 這本書中的一些比較重要的概念,配合實例講解一次。可以跟著教程把示例敲一次,在 vscode 中多看看給出的提示,看完之后,對 TS 的一些核心概念,肯定會有更深的理解。
模仿和實踐想要真的掌握 TS,少不了實踐。模仿也是一種好的實踐方式,已 React + TypeScript 為例,比較推薦的模仿內容如下:
TypeScript-React-Starter ,這是微軟為 TS 初學者提供的一個非常好的資料,可以繼續使用我們上面構建的 playground ,參照這個倉庫的 readme 寫一次,差不多就能知道 TS 結合 React 的基本用法了;
GitHub - react-typescript-cheaTSheet,這個教程也比較簡單,不過上面那個教程更近了一步,依據其 readme 繼續改造我們的 playground 后,我們能知道,React + Redux + TypeScript 該如何配合使用;
react-redux-typescript-guide ,這個教程則展示了基于 TypeScript 如何應用一些更復雜的模式,我們也可以模仿其提供的用法,將其應用到我們自己的項目中;
Ultimate React Component Patterns with Typescript 2.8 ,這篇文章則可以做為上述內容的補充,其在掘金上有漢語翻譯,點贊量非常高,看完之后,差不多就能了解到如果使用 TS 應對各種 React 組件模式了。
Use TypeScript to develop React Applications — egghead.io,隨后如果想再輕松一點,則可以再看看這個網課,跟著別人的講解,回頭看看自己模仿著寫的一些代碼,也許會有不同的感觸;
至此,你肯定就已經具備了基礎的 TS 開發能力,可以獨立的結合 TS 開發相對復雜的應用了。
更深的理解當然也許你并不會滿足于會用 TS,你還想知道 TS 的工作原理是什么。這時候推薦閱讀下面兩篇內容:
TypeScript Compiler Internals · TypeScript Deep Dive ,TS 編譯的核心還是 AST,這篇文章講解了 TS 編譯的五個階段( Scanner /Parser / Binder /Checker /Emitter )分別是怎么工作的;
Learn how to contribute to the TypeScript compiler on GitHub through a real-world example,則是另外一篇比較好的了解 TS 運行原理的資料。
關于 TS 的原理,我還沒有來得及仔細去看。不過 AST 在前端中的應用還真是多,待我補充更多的相關知識后,也許會對 AST 有一個更全面的總結。
TS 當然也不是沒有缺點,The TypeScript Tax 是一篇非常優秀的文章,閱讀這篇文章能讓我們更為客觀看待 TS,雖然站在作者的角度看,TS 弊大于利,主要原因是 TS 提供的功能大多都可以用其它工具配合在一定程度上代替,而且類型系統會需要寫太多額外的代碼,類型系統在一定程度上也破壞了動態語言的靈活性,讓一些動態語言特有的模式很難在其中被應用。作者最終的結論帶有很強的主觀色彩,我并不是非常認可,但是這篇文章的分析過程非常精彩,就 TS 的各種特性和現在的 JS 生態進行了對比,能讓我們對 TS 有一個更全面的了解,非常推薦閱讀,也許你會和我一樣,看完這個分析過程,會對 TS 更感興趣。
TS 每隔幾個月就會發布一個新的小版本,每個小版本在 TypeScript 官方博客 上都會有專門的說明,可用用作跟進學習 TS 的參考。
參考下述參考內容在文中,都有鏈接,如果都看過,則無需再重復查看了。
TypeScript handbook — book
TypeScript Deep Dive — book
TypeScript-React-Starter — github
react-typescript-cheaTSheet — github
Advanced Static Types in TypeScript — egghead.io
Use TypeScript to develop React Applications — egghead.io
Practical Advanced TypeScript — egghead.io
Ultimate React Component Patterns with Typescript 2.8 — medium
The TypeScript Tax — medium
你也可以來知乎專欄和我討論
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103788.html
摘要:怎么影響了我的思考方式對前端開發者來說,能強化了面向接口編程這一理念。使用的過程就是在加深理解的過程,確實面向接口編程天然和靜態類型更為親密。摘要: 學會TS思考方式。 原文:TypeScript - 一種思維方式 作者:zhangwang Fundebug經授權轉載,版權歸原作者所有。 電影《降臨》中有一個觀點,語言會影響人的思維方式,對于前端工程師來說,使用 typescript 開...
摘要:眾所周知,在大公司中進行大的改革很難。目前公司有超過名開發人員,其中有個以上是前端。從年起,已經在一些小規模團隊中探索使用。在年的前端調查中,靜態類型系統呼聲最高。在我們的主倉庫中,絕大多數的公共依賴都已經由做到了類型聲明。 特別說明 這是一個由simviso團隊進行的關于Airbnb大規模應用TypeScript分享的翻譯文檔,分享者是Airbnb的高級前端開發Brie Bunge ...
摘要:系列引言最近準備培訓新人為了方便新人較快入手開發并編寫高質量的組件代碼我根據自己的實踐經驗對組件設計的相關實踐和規范整理了一些文檔將部分章節分享了出來由于經驗有限文章可能會有某些錯誤希望大家指出互相交流由于篇幅太長所以拆分為幾篇文章主要有以 系列引言 最近準備培訓新人, 為了方便新人較快入手 React 開發并編寫高質量的組件代碼, 我根據自己的實踐經驗對React 組件設計的相關實踐...
摘要:使用官方的的另外一種版本和一起使用自動配置了一個項目支持。需要的依賴都在文件中。帶靜態類型檢驗,現在的第三方包基本上源碼都是,方便查看調試。大型項目首選和結合,代碼調試維護起來極其方便。 showImg(https://segmentfault.com/img/bVbrTKz?w=1400&h=930); 阿特伍德定律,指的是any application that can be wr...
閱讀 1010·2021-11-22 13:52
閱讀 924·2019-08-30 15:44
閱讀 570·2019-08-30 15:43
閱讀 2424·2019-08-30 12:52
閱讀 3473·2019-08-29 16:16
閱讀 637·2019-08-29 13:05
閱讀 2943·2019-08-26 18:36
閱讀 1975·2019-08-26 13:46