如何用 TypeScript 提高 JS 工程的健壯性?
瀉藥。。@vilicvane 已經說的比較詳細了,這裡在補充一些小技巧。。
let error: [number, string] = [123, "Some Message"];
在 TypeScript 的類型標註中,當我們把類型寫在方括弧之前,就是 Typed Array,當類型寫在方括弧之中,就是 Typed Tuple 了。接著我們就可以使用類型安全的方式解構或者手動取值:
// Both correctly typed
let [code, message] = error; // code is number and message is string
let anotherCode = error[0]; // anotherCode is number
let anotherMessage = error[1]; // anotherMessage is string
class Socket {
on (event: "open" | "message" | "error" | "close", cb) {
// ...
}
}
let mySock = new Socket();
socket.on("message", () =&> {});
function log(message: string): void {
// ...
}
4. Implements Class
對於面向對象編程,組合優於繼承,但是對於組合,我們往往需要先定義一個介面類型,然後再定義一個這個介面的實現類型,十分繁瑣。在 TypeScript 中,我們可以直接 Implements(而非 extends)一個(或多個)類:class Base1 {
method1 () {}
}
class Base2 {
method2 () {}
}
class MyClass implements Base1, Base2 {
constructor (private base1: Base1, private base2: Base2) {}
method1 () { return this.base1.method1(); }
method2 () { return this.base2.method2(); }
}
...In practice, it"s best to avoid the terms "strong" and "weak" altogether, because
- Amateurs often conflate them with "static" and "dynamic".
...
謝邀.這個問題感覺很難回答. 我大致說說我的一些個人習慣, 和代碼健壯性還是算稍有關聯.
- 開啟 noImplicitAny, noImplicitReturns, 最新的版本里開啟 noImplicitThis, strictNullChecks.
- 有同學已經提到, 少寫 any, 但這樣或許還不夠. 生產環境的代碼避免直接使用類型為 any 的值, 即使它被明確聲明為 any 類型. 在使用前可以進行一次類型轉換如: (value as Type).property; (map[index] as Type).property. 這個習慣可以確保引用查找和重命名的準確.
- 與上一條對應, 在可能有多種類型時使用聯合類型 (Union Type), 方便 TypeScript 的類型收窄機制自動收窄到某一具體類型 (目前 TypeScript 不會對 any 類型進行收窄, 這一點可能未來會有變化). 如果自動的類型收窄不能完美處理, 處理方法同上.
- 為所有方法顯示標註返回值類型.
其實 TypeScript 對能正常運行的代碼的健壯性有直接貢獻的地方我認為就是跟控制流相關的錯誤分析和類型收窄了. 但這一點一定程度上是需要和代碼書寫的靈活性平衡的. 當然最近 TypeScript 在這方面帶來了不少改進, 有興趣的同學可以上手玩玩看最新的 nightly build.
相關文章
TypeScript 類型收窄與基於控制流的類型分析 - JavaScript in TypeScript - 知乎專欄TypeScript 中的 Non-nullable 類型 - JavaScript in TypeScript - 知乎專欄謝邀,我就寫一些最佳體驗建議吧;
1、對於剛入門的同學,請單純的使用ts和js一比一的編譯模式(即一個ts文件編譯出同名的js文件,能不用tsconfig.json 配置文件就不用,因為對於大部分js開發場景這是最單純且不容易引入其它門檻的方法;2、開始上正餐,強類型化你的AJAX介面,即為每一個AJAX請求的參數和返回類型做定製的interface,當然這也是有技巧的,同時也會影響你的服務端介面設計;
舉個例子,我們先假定你的服務API沒有用RESTful風格的設計(即在url中間帶參數,並且用很多的http method如Put、Delete),好好的單純用POST,只用POST,並且參數都是在Request Body里的JSON;我們先建立一個webapi.d.ts的文件,把所有WebAPI的報文結構定義在這裡;第二個文件,http.ts, 這裡用到了API工廠方法設計,createAPI函數有兩個泛型模版TReq和TRes分別用來約束請求參數和返回類型,然後剛才我們定義的WebAPI的數據結構,在這裡被設計成兩個API的實現: getItemById和getItems,實際請求的功能使用jQuery實現的,這裡就不做細講了;
再寫一點收工;
3、巧妙使用聯合類型;JS開發中,我們經常需要對JSON對象進行屬性擴展,如果是強類型的就不方便了,在這裡使用中括弧肯定會被吐槽,可以試試隨寫隨用的聯合類型;假定我們的業務場景里有一個列表視圖,然後要用一個欄位來表示某一個數據行被選中了,那麼我們就可以給原來的JSON結構擴展一個$checked屬性了(這裡加$只是我的命名習慣),上面兩種寫法都可以,TS的類型聲明表達式真是帥呆了,活用和|關鍵字可以寫出靈活又健壯的代碼,而這些類型代碼編譯到JS就只是空氣而已;雖然說js里給對象隨便加屬性很常見,不過開發一時爽,維護火葬場;先到這裡了,為什麼把api的數據結構專門放在d.ts文件里?因為可以跨項目引用啊,也許你的nodejs代碼也需要它,用js寫的手機App項目(Cordova/React Native)也需要它,反正d.ts運行時不載入的,真正做到一處編寫,到處使用,划算!使用和優化上說不出太多,才接觸沒多久,寫Angular2項目時用過。
只是有一點,TS可以很好地建立Reusable Component,只要做好值的傳輸(input和output),就可以把每個組件寫活,進而在項目中重複利用。Angular1,我覺得provider可以、達到類似的效果,但其實模塊化做的遠不如用TS寫的Angular2項目好。個人感覺NG1的Provider其實只是方法或者邏輯的封裝,不涉及View層。而NG2在這方面可以說是一大突破。因此用TS寫的時候,最好多考慮考慮這一點。
一個朋友跟我說,現在的趨勢就是這樣:前端Reusable,後端Extendable。共勉隨便談談想到的幾個點,想到哪裡寫到哪裡:
1.TypeScript最大的優勢在於能已很少的成本為你的javascript設計加上相當不錯的編譯時類型檢查。所以這個問題其實是個如何善用類型檢查的問題。
2.如其它答主所言,少用any,盡量聲明類型。到處都是any的typescript其實就是javascript
3.善用匿名類型。在javascript中我們常常會把一組變數用{}括成一個對象便於傳遞訪問,在Typescript里這種情況務必要為變數聲明加上匿名類型定義,如果用的地方多了還可以提出來聲明為一個介面。
4.別漏了聲明回調函數的簽名。TypeScript做編譯檢查的時候允許你忽略一部分回掉函數的傳入參數,所以使用強類型的回調函數不會影響你的代碼靈活性
5.為所有和服務端通信用到的plainobject定義介面類型。注意介面成員可以加上「?」來允許忽略,所以在這裡使用強類型這不會增加你的代碼量
6.使用老的javascript代碼或者外部javascript庫的時候一定要帶類型聲明。多數流行js庫都有typescript類型聲明文件,實在找不到或者是js代碼是自己的老代碼的話,自己寫類型聲明文件吧,反正也不麻煩,就寫自己用到的部分就好。
7.如果你是從C#/Java等強類型語言轉過來的,務必記得typescript是本質上是一門存粹的動態語言,別忘了享受動態語言的特性帶來的好處。不要用[""]來訪問私有屬性或私有方法
把tslint報的錯都改正
推薦閱讀:
※ui-route實現頁面跳轉回來頁面不重新載入?
※如何評價 Node v6.0.0 (Current) ?
※一些網站能自動添加 URL 到 Safari 的閱讀列表,這是如何實現的?
※有哪些目前流行的前端框架?
※ES6的class關鍵字有沒有實現真正的面向對象?
TAG:JavaScript | TypeScript |