延續上一篇 TS 筆記末尾,若版本允許,使用 unknown 會比 any 更好一點,此篇就來簡介一下 unknown:
unknown
unknown 型別容易與 any 搞混,其在 TypeScript 3.0 版提出,也是所有型別的聯集。unknown 意指未知型別,表示不知道當下是何種型別。使用 unknown 會允許 TypeScript 在之後仍可以賦值為任意型別。
unknown 和 any 的差異:
- 不能直接操作屬性、方法、建構式
- 無法重新賦值給 unknown 或 any 外的型別
- 需要斷言或限縮型別
不能直接操作屬性、方法、建構式
在使用 any 的情境下,我們可以這樣寫,即便數值 1 根本沒有 somethingMethod 這個方法,TypeScript 仍不會報錯可以正常編譯。
let anyValue: any = 1;
anyValue.somethingMethod();
改成 unknown 的情境下,就嚴謹許多,也會出現錯誤。
let unknownValue: unknown = 1;
unknownValue.somethingMethod(); // 出現警告波浪~
無法重新賦值給 unknown 或 any 以外的型別
一但註記 unknown 型別,後續賦值給另外註記 unknown 與 any 變數正常不會報錯:
let unknownValue: unknown;
let foo1: unknown = unknownValue;
let foo2: any = unknownValue;
但是賦值給 unknown 或 any 以外的型別就會報錯:
let unknownValue: unknown;
let foo1: number = unknownValue;
let foo2: string = unknownValue;
需要斷言或限縮型別
一旦變數註記了 unknown,下次使用該變數就要做型別斷言或能讓編譯器做出型別檢查,目的是為了限縮型別,畢竟 unknown 表示未知,不這麼做編譯器會報錯擋著。
例如:
let anyNumber: any = 123;
let unknownNumber: unknown = 123;
anyNumber + 1;
unknownNumber + 1; // 出現警告波浪~
unknownNumber 出現錯誤提示訊息,所以必須要給其斷言才行。
let anyNumber: any = 123;
let unknownNumber: unknown = 123;
anyNumber + 1;
(unknownNumber as number) + 1;
// 或者
<number>unknownNumber + 1;
然而,若將上述改成 unknown 與 string 的相加
let anyString: any = "123";
let unknownString: unknown = "123";
anyString + "1";
unknownString + "1"; // 沒有警告波浪~
編譯器這邊推論給過,筆者查閱文件和網路文章沒有看到原因,後來在 FB TypeScript Taiwan 社團發問得到版主的解釋,大意如下:
number 與 + 運算子搭配,出來的結果是不確定的,尤其是在與 unknown 不確定為合的情境下相加,自然需要斷言。
然而大部分型別用 + 運算子跟 string 型別結合都會變成 string,所以編譯器自然就給過了。
總之,雖然 unknown 和 any 很像,但如同其他網路文章所說的,unknown 像是更安全的 any,開發者若為了自己開發習慣或要改動陳年舊 code,使用 unknown 還比使用 any 好一點。
當下次 JS 社群或靠北工程師又有反對 TS 的鄉民酸「any 啦,我都用 any」,你可以告訴他:「我都用 unknown」
參考
FB社團:TypeScript Taiwan
TypeScript 新手指南
TypeScript: Typed JavaScript at Any Scale.
kobo 電子書:讓TypeScript成爲你前端開發的ACE!
Typescript 初心者手札