never
:各種型別的 subtype。假設型別註記為 boolean
,還是有可能被型別推論為 never
,表示這個變數或函式有一些條件狀況可能未被處理。
any
:通常只在導入 TS 初步除錯時使用,開發專案時 盡量別!使!用!
unknown
:似 any
,但 unknown
型別的變數值,只能指派給 any
或 unknown
型別的變數。
–
通常有兩種情況會使用此型別:
沒辦法跳脫函式的狀況,最直觀就是函式內發生了無窮迴圈:
不過通常很難第一時間就發現,程式因某個條件而導致的無窮迴圈。看到這裡,有些人可能會以為是 TS 檢測時進行 型別推論
才會需要 never
型別來警告。
其實不然,再看一個會造成 never
型別的範例:
在嚴格模式下,會造成某些條件(else
)沒有返回值,這種函式就會被推論為 boolean
下的 never
型別。
提醒:
never
是各種型別的 subtype。
如果傳值符合條件,回傳了 true
(boolean
),就與型別推論結果(never
)產生衝突,導致 TS 報錯,因此,比較常見的作法,我們會在最後 return
一個 never
型別的東西。
那麼,我們試著在函式最後,再加上一段語法,針對不符合任何條件的結果,拋出一個錯誤訊息。
事實上這個動作其實很常見,尤其是在 try...catch
的語法中。因此,我們通常將它寫成 function
:
回憶一下 <Day02:型別系統 - 原始型別 Primitive Types> 我們有說明過的 void
。
你會發現這裡並不是使用 void
作為型別註記,因為 throw new Error
還是算一個回傳值。
所以如果我們這麼做:
這時候就會由於回傳的 throwError()
是 never
型別,與 checkData()
型別推論一致,最終通過 TS 的型別檢測。
–
在既有專案導入 TypeScript 時,會因 JS 本身沒有型別註記,而出現預期性錯誤,在正式開發前,我們會習慣先將所有的型別註記為 any
,這可以讓 TS 跳過型別檢測,讓專案可以先正常運作。
注意:
any
會讓 TS 跳過型別檢測!
這代表註記 any
只是為了讓整個格式符合 TS 的撰寫方式,它還是會跟 JS 一樣,容易引發非預期的錯誤。
所以導入與修正型別,並確定程式可運作後,請 盡可能 依序將每個 any
型別重新註記為適當的型別。
既然說「盡可能」,當然就會有一些例外。
實務上,確實會有型別無法確定的狀況,像是 JSON.parse
,每一個屬性都有不同的型別,除非 屬性
,值
都是確定的,可註記為 object
,除此之外也只能用 any
。
–
有兩個重點需要瞭解:
unknown
型別的變數特性與 any
型別類似,兩者相同之處在於,變數可以接收任何型別的值:
而相異處則是
any
型別的變數值,可以指派給任何型別的變數
unknown
型別的變數值,只能指派給any
,unknown
型別的變數
將 any
型別變數值,指派給任何型別的變數:
將 unknown
型別變數值,指派給任何型別的變數:
–
unknown
型別的變數特性假設有個變數 setSomething
,我們將某個 unknown
型別的變數值指派給 setSomething
。
這時,
setSomething
不可呼叫任何方法或屬性,也不可作為參數傳入函式或方法。setSomething
不能被指派給型別為 T 的變數,其中 T 不為unknown
或any
。
我們用實例來看看是什麼意思:
當我們將一個被註記為 unknown
的 safeParseJSON()
,指派給 parseToSafeJSON
,這時 parseToSafeJSON
其實無法呼叫任何方法或屬性。
unknown
或 any
還記得在變數指派限制中,我們就有舉過 unknown
指派的例子嗎?
我們宣告一個型別為 T
的變數,這裡的 T
,可以是任何不為 unknown
或 any
的型別,我們就以 number
型別為例:
以結果來看,我們確實無法將 unknownType
指派給 setNumber
。
–
unknown
型別的複合特性任意型別與 unknown
型別進行 &
(交集),就會成為任意型別:
除了 any
外,任意型別與 unknown
型別進行 |
(聯集),就會成為 unknown
:
系列:
跑完 JS30 就接著認識 TypeScript 入門
上一篇:Day04:型別系統 - 明文型別 Literal Types 與 型別化名
下一篇:Day06:型別系統 - 複合型別 Composite Types
跑完 JS30 就接著認識 TypeScript 入門