前言
話說"動態類型一時爽,代碼重構火葬場",雖然有很多不同的意見(請參考),但我們看到勢頭強勁的TypeScript和Flow.js,也能感知到靜態類型在某程度上能幫助我們寫出更健壯的代碼(當然要基于充分的單元測試上啦)。
ClojureScript與JavaScript一樣采取動態類型,但由于需要通過Google Closure Compiler編譯后才能運行,因此我們可以如同JS那樣借助GCC的注解來引入編譯時類型檢查,達到同樣靜態類型的效果。
配置項目設置
GCC的編譯時類型檢查僅當optimizations
為simple
或advanced
時有效。我們以:cljsbuild
下的dev配置為例
:cljsbuild
{:builds
[{:id "dev"
:main type-check.core
:output-to "resouces/public/js/type_check.js"
:optimizations :simple
:source-map "resources/public/js/type_check.js.map"
:closure-warnings ;; 設置GCC編譯時類型檢查
{:check-types :warning ;; 務必設置為warning
:undefined-names :off ;; 屏蔽goog庫的異常信息
:externs-validation :off ;; 屏蔽goog庫的異常信息
:missing-properties :off ;; 屏蔽goog庫的異常信息
}}]}
請注意,:check-types
必須設置為:warning
,若設置為:error
時,就會報Math.imul引發的JSC_DUP_VAR_DECLARATION_TYPE_MISMATCH異常
,導致項目其他代碼均不能被編譯。希望大神指點迷津~~
注解語法
首先GCC用到的注解語法僅為JSDoc的子集,所以直接看GCC的注解即可,而ClojureScript一般就用如下幾個
@private {Type}
標識私有成員,且該成員的數據類型
@type {Type}
標識成員的數據類型
@param {Type} varname Description
標識函數的型參的數據類型,參數名和描述
@return {Type} Description
標識函數返回值的數據類型和描述
@throws {Type}
標識函數可能拋出異常類型
接下來就是重點了,我們寫了這么多還不就是想引入數據的類型描述嗎?那關鍵就是上述代碼中Type到底應該怎么寫了!
1.標量類型number
,string
,boolean
,null
,undefined
注意
一、標量類型默認表示變量或參數的實際值為不可為null(non-nullable)。若要標識為可為null(nullable),那么只需前置一個問號?
即可(?number
,?string
)
2.對象類型Object
,Function
,Number
,String
,Boolean
,Date
和其他Cljs或自定義的對象類型。
注意
一、對于非全限定的對象類型,會自動展開為當前命名空間的類型(如當前命名空間為my-proj.core
,那么MyArray
會展開為my-proj.core/MyArray
)
二、對象類型默認表示變量或參數的實際值可為null(nullable)。若要標識為不可為null(non-nullable),那么只需前置一個感嘆號!
即可(如!Object
,!Date
等)
3.組合類型,如(number|string)
,即是實際值可為數字也可為字符串。
4.集合/字典,Array<Type>
表示為數組類型且其元素類型可以繼續遞歸下去,Object<Type>
表示為對象類型且鍵類型為Type,Object<Type1,Type2
表示為對象類型且鍵類型為Type1而值類型為Type2
5.函數類型
function(Type1,Type2)
,表示函數含數據類型為Type1和Type2兩個形參。
function(Type1,Type2):Type3
,表示函數含數據類型為Type1和Type2兩個形參,且返回值類型為Type3。
function(...Type)
,表示函數含數據類型為Type的可變形參,注意可變形參必須作為最后一個形參出現。
function(Type=)
,表示函數含可選的數據類型為Type的形參,注意可選形參后不能聲明必填的形參。
注意注意!
- 形參和逗號間千萬不要留空格,否則編譯時會報警告的哦!
Type為function()時不能在聲明返回值類型,否則編譯時輝報警告!
@param {function(*,function(*):number)} 是不允許的 @param {function(*,function(*))} 只能這樣寫啦
6.什么類型都可以,
*
實例
1.封裝chrome.runtime.onMessage玩玩
(defn on-msg
"@param {function(*,window.MessageSend,function(*))} handler
@return {null}"
[handler]
(let [this (.. js/chrome -runtime -onMessage)]
(.addListener this
(fn [a b c]
(handler a b c)
true))))
注意:window.MessageSend
既不是GCC內置的類型也不是我們自定義類型,而是外部定義的數據類型,因此我們需要添加externs文件讓GCC識別。
因此得到的配置如下
:cljsbuild
{:builds
[{:id "dev"
:main type-check.core
:output-to "resouces/public/js/type_check.js"
:optimizations :simple
:source-map "resources/public/js/type_check.js.map"
:externs ["externs/chrome.js" "externs/chrome_extensions.js"]
:closure-warnings ;; 設置GCC編譯時類型檢查
{:check-types :warning ;; 務必設置為warning
:undefined-names :off ;; 屏蔽goog庫的異常信息
:externs-validation :off ;; 屏蔽goog庫的異常信息
:missing-properties :off ;; 屏蔽goog庫的異常信息
}}]}
總結
如官網所講,這部分的內容仍在發展階段,所以還有很多不完善的地方。不過也不影響我們現在就開始使用,因此良好的代碼注釋從來都需要的!
尊重原創,轉載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/7625414.html ^_^肥仔John
參考
https://clojurescript.org/reference/compile-time-type-checking
https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler
https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System
https://github.com/google/closure-compiler/wiki/Warnings
文章列表