“
字數:1712字 閱讀: 3 分鐘
大家好,今天和大家聊下讓我曾經迷惑的兩個TS類型:unknown 和 never,不知道大家有沒有對其用法有所迷惑呢,好記性比不過爛筆頭,為了讓我不再迷惑,還是通過文字的形式整理下加深下印象比較靠譜,希望今天的分享能給大家解惑。
一、unknown 類型unknown 類型是 TS3 新增的類型,這個類型與 any 類型類似,可以設置任何的類型值,随後可以更改類型。因此,我們可以将變量先設置為字符串類型,然後再将其設置為數字類型,如果事先不檢查類型,使用any類型,調用了不存在的方法,編譯時不會報錯,代碼運行時才會發現錯誤。但是使用unknown 類型不一樣,如果不進行類型判斷,執行相關操作編譯器就會報錯。文字說了這麼多,還是上代碼,更容易理解些。
1、關于 Any 的問題首先我們創建一個 any.ts 的文件,代碼如下:
letval:any=22;
val="stringvalue";
val=newArray();
val.push(33);
console.log(val);
運行編譯後的代碼,并不會報錯,也是按照我們的預期輸出: [33]
由于是 any 類型,我們可以随意更改類型,當變成數組類型時,我們調用push方法進行内容操作,看似沒啥問題,如果我們開發人員,如果由于疏忽,打錯了一個不存在的方法,ts代碼能正常編譯嗎?
letval:any=22;
val="stringvalue";
val=newArray();
val.doesnotexist(33);
console.log(val);
當運行 tsc any 命令後,你會發現編譯器能順利編譯,當我們運行 node any,編譯後的代碼能正常執行嗎?答案是顯而易見的,會報異常,你會在控制台發現以下錯誤:
val.doesnotexist(33);
^
TypeError:val.doesnotexistisnotafunction
上述的錯誤,大家可能不會犯,但是項目大時,參與的人多時,就很難避免這樣類似的問題,因此unknown 類型出現了。
2、一段 unknown 類型的代碼接下來我們來看看它是怎麼解決類似的問題,我們還是從一段簡單的代碼開始,如下段代碼所示:
letval:unknown=22;
val="stringvalue";
val=newArray();
val.push(33);
console.log(val);
當你編譯此代碼時,你會立馬收到如下報錯:
Property'push'doesnotexistontype'unknown'.
是不是很奇怪,雖然我們将其類型更改為數組類型,但是編譯器不認識,它認為unknown類型,這個類型沒有push方法,當然會報錯,除非先判斷類型,如果是相關類型且正确執行相關方法,編譯器則會順利通過,如下段代碼所示
letval:unknown=22;
val="stringvalue";
val=newArray();
if(valinstanceofArray){
val.push(33);
}
console.log(val);
雖然有些麻煩,但是相比 any 類型說,更加安全,在代碼編譯期間,就能幫我們發現由于類型造成的問題,因此在大多的場景,建議使用 unknown 類型替代 any。
二、never 類型這個類型看起來有些奇怪,乍一看,看起來和void相似,但是其完全不一樣。從字面意思上來說,表示一個從來不會有返回值的函數(例:while(true) {}),一個總是會抛出錯誤的函數(function foo() { throw new Error('Not Implemented') })。那麼問題來了,它和 void 類型啥區别,void 表示沒有任何類型,函數沒有返回值時(可以返回,但是沒值),我們可以設置為void 類型;never這不一樣,一個函數根本就沒返回(或者總是出錯,永遠不會有返回值)。看文字有些費勁,我們還是來看一段簡單的代碼來理解下吧,如下所示:
functionalwaysThrows():never{
throw"thiswillalwaysthrow";
return-1;
}
當我們編譯上述代碼時,編譯器就會報錯,如下所示:
Type'number'isnotassignabletotype'never'.
編譯器已經很明确地告訴了我們 never 類型不應該返回任何值(或抛異常)。那麼問題來了,這個類型有啥用呢?我們還是舉個例子來理解下吧,比如你有個 enum 枚舉類型,代碼如下所示:
enumTestNeverEnum{
FIRST,
SECOND
}
在 switch 當中判斷 type,TS 是可以收窄類型的 (discriminated union):
enumTestNeverEnum{
FIRST,
SECOND
}
functiongetEnumValue(value:TestNeverEnum):string{
switch(value){
//這裡value被收窄為TestNeverEnum.FIRST
caseTestNeverEnum.FIRST:return"Firstcase";
//這裡value被收窄為TestNeverEnum.SECOND
caseTestNeverEnum.SECOND:return"Secondcase";
//returnValue是never類型
default:constreturnValue:never=value;
}
}
注意在 default 裡面我們把被收窄為 never 的 returnValue 賦值給一個顯式聲明為 never 的變量。如果一切邏輯正确,那麼這裡應該能夠編譯通過。但是假如有一天你的同事增加了TestNeverEnum 枚舉類型:
enumTestNeverEnum{
FIRST,
SECOND,
THIRD
}
然而他忘記了在 getEnumValue 裡面加上針對 THIRD 的處理邏輯,這個時候在 default branch 裡面 returnValue 會被收窄為 TestNeverEnum.THIRD,導緻無法賦值給 never(因為有值返回),産生一個編譯錯誤。編譯器會産生如下的錯誤:
Type'TestNeverEnum'isnotassignabletotype'never'.
所以通過這個辦法,你可以确保 getEnumValue 方法裡總是窮盡 (TestNeverEnum) 了所有 All 的可能類型,目的就是寫出類型絕對安全的代碼。
三、結束語今天的内容就到這裡,這兩個類型你弄明白了嗎?雖然内容不多,但是需要細品 ,才能理解其應用場景和用好它們,感謝的閱讀。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!