前一天我們有提到型別聯集(Union Types),也有提到他帶來的好處跟需要注意的地方,需要使用型別間”共有”的方法,但只要透過型別防衛(Type Guard),我們便能穩當的去使用指定型別的方法,而不用受限於共有的。
我碰到這情境的第一個想法是:「那我的程式碼內,豈不是要一直出現if…else…
,或者是switch(條件)
?要是TypeScript在compile時能幫我去除掉那些block,倒還算人性化,但要是那些判斷式都留著,整個程式碼看起來不就會很亂嗎?」
初學如我如果有想到這種情境,那些更資深的開發者怎麼可能沒想到這件事呢,我們接下來要講的型別斷言(Type Assertion)便恰巧解決了我的疑慮。
(下面這例子取自《TypeScript 邁向專家之路:零基礎 JavaScript 打通 Angular、React 與 Vue.js 前端框架實戰》的7-19頁,並簡化了一些)
function priceConvert(price: number, format: boolean) {
return format ? `$${price.toFixed(2)}` : price
}
let priceNumber = priceConvert(500, false)
let priceString = priceConvert(500, true)
console.log(priceNumber.toFixed(2))
console.log(priceString.charAt(0))
這段程式碼並不難讀,我們宣告了數字版跟字串版的兩個變數priceNumber
與priceString
,並且對他們執行數字特有的方法及字串特有的方法。儘管我們這邊並沒有”明確”寫出priceConvert的回傳值型別是什麼,但TypeScript已經能從我們的三元運算子中,推斷出回傳的值是個字串與數字的聯集。
既然回傳值可能是字串或數字,那我們後來想對priceNumber
跟priceString
進行特定型別的方法,就有可能會出錯。
在不特地用上型別防衛的情況下,我們可以使用型別斷言。
let priceNumber = priceConvert(500,false) as number
let priceString = priceConvert(500,true) as string
意思大致上是說:「TypeScript我跟你說,這個priceNumber
/priceString
是個數字/字串啦,我等等對priceNumber
/priceString
做各種數字/字串才會做的事,你就睜一隻眼閉一隻眼就好了。」
結果,TypeScript真的不再發出警告訊息了!真是聽話呢(?)
值得注意的是,這邊下了斷言,不代表我們對這個值進行了任何”強制型別轉換”唷。如果priceNumber
的型別是number
,但我們卻還是斷言他是string
,並在後續的程式碼中對他做了字串才有的方法,就算在畫面上錯誤(紅色波浪底線)消失了,但真正在執行時,由於數字沒有字串的方法,就會報錯。而這種情況是我們不樂見的,畢竟使用TypeScript就是想在compile前抓出錯誤。
讓我們再看個情境,要是我們(不管出於什麼原因)想斷言priceNumber
是個boolean
呢?
OKOK,TypeScript噴錯了,它表示:「你要將可能是number
或是string
的值,斷言成boolean
?你一定有什麼地方搞錯了吧?畢竟boolean
跟number
或string
並沒有聯集啊!啊如果你真的是故意要這樣做的話,那就先把這個值斷言成unknown
吧!」
這邊TypeScript說的「先把他斷言成unknown
」,有一點偷吃步的味道在。
let priceNumber = priceConvert(500, false) as unknown as boolean
console.log(priceNumber) //500
也就是,我們先把priceNumber的值斷言成"未知",既然他是未知,他當然可以被斷言是boolean
,就跟未知的人生,什麼都有可能發生一樣(?)。剛剛提過,斷言不會進行強制轉型,所以就算我們印出priceNumber
,也不會得到true/false
,而是得到正確的執行結果500
。
我自己還不確定到底實際在開發專案時,有什麼情況得用到這招,但既然TypeScript都這樣提示了,或許可以留意一下這個用法(如果讀者你/妳曾使用過,拜託跟我分享一下)。
–
今天簡單介紹了型別斷言,還提到了unknown
,那明天就來講講unknown
以及其他特殊一點的型別吧,我們明天見!