TypeScript基礎(chǔ)——基本類(lèi)型檢查

?? 為什么要使用TypeScript?
JavaScript設(shè)計(jì)之初只是為了補(bǔ)充Java的,在瀏覽器上做一些小的效果,并不是為了做大型復(fù)雜項(xiàng)目而開(kāi)發(fā)的,js本身也是有很多缺陷的,關(guān)于為什么要用TS,小伙伴們可以瞅瞅這篇文章 :我們?yōu)槭裁匆獙W(xué)習(xí)TypeScript ?
?? 基本類(lèi)型檢查
1. 如何進(jìn)行類(lèi)型約束
類(lèi)型約束其實(shí)很簡(jiǎn)單,只需要在變量、函數(shù)參數(shù)、函數(shù)返回值位置上加上:類(lèi)型就可以了。
舉個(gè)栗子??: 變量
//我們定義變量的時(shí)候,肯定是知道這個(gè)變量是存放什么類(lèi)型的數(shù)據(jù)
let name:string = "法醫(yī)";
一旦給 name 賦值其它類(lèi)型,立馬會(huì)提示錯(cuò)誤

舉個(gè)栗子??: 函數(shù)參數(shù)和返回值
//參數(shù)后面 :number表示傳的參數(shù)必須是數(shù)字類(lèi)型,而test函數(shù)后面的 :number表示返回值是數(shù)字類(lèi)型
function test(a:number,b:number):number {
return a + b;
}
test(1,2);//當(dāng)調(diào)用test函數(shù)傳值為數(shù)字表示可以正常運(yùn)行,傳其它類(lèi)型則會(huì)報(bào)錯(cuò)
傳入字符串就會(huì)報(bào)錯(cuò)

當(dāng)我們寫(xiě)一個(gè)函數(shù)的時(shí)候,我們非常清楚函數(shù)的參數(shù)以及返回值是什么類(lèi)型的,此時(shí)我們可以約束好類(lèi)型,在之后的調(diào)用中我們可以放心的調(diào)用函數(shù),因?yàn)橹灰獙?xiě)錯(cuò)了,立馬會(huì)提示錯(cuò)誤,不需要等到程序運(yùn)行后再提示錯(cuò)誤,這些在JS中是做不到的,但是在TS中很輕松可以做到,不僅如此,類(lèi)型檢查還帶來(lái)很多好處,比方說(shuō):
舉個(gè)栗子??:
在JS中我們是沒(méi)有辦法確定下面代碼中text(1,2)調(diào)用的就是一個(gè)函數(shù),中途有可能test會(huì)被修改,然后調(diào)用函數(shù)就會(huì)報(bào)錯(cuò)
function test(a,b) {
return a + b;
}
// 很多行代碼
test = 123;
// 很多行代碼
test(1,2);

但是在TS中這種情況絕對(duì)是不允許的,“呦呦,切克鬧,我是TS,不允許鴨不允許”??

由于TS知道函數(shù)test和調(diào)用函數(shù)test是同一個(gè)東西,于是就出現(xiàn)一個(gè)神奇的效果——當(dāng)需要給函數(shù)重新命名的時(shí)候,雙擊函數(shù)test并且按F2,函數(shù)名改了,調(diào)用函數(shù)名也跟著改了,之所以會(huì)達(dá)到這個(gè)效果,是因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">TS有嚴(yán)格的類(lèi)型檢查系統(tǒng),它知道調(diào)用函數(shù)的test用的就是test函數(shù),它們兩者之間是建立聯(lián)系的

不僅如此,還有一種效果:當(dāng)我們點(diǎn)擊調(diào)用函數(shù)并且按F12,它會(huì)跳到定義的函數(shù)位置,

為了讓我們少寫(xiě)點(diǎn)代碼,使用TS進(jìn)行約束的時(shí)候,TS在很多場(chǎng)景中可以完成類(lèi)型推導(dǎo)
舉個(gè)栗子??:
當(dāng)我們把函數(shù)返回值約束去掉以后依然可以從提示中發(fā)現(xiàn)返回值是number,這是因?yàn)槲覀儗?shù)約束為number,數(shù)字與數(shù)字相加依然是數(shù)字,所以最后函數(shù)也會(huì)返回number,賦值給變量result,TS還會(huì)智能地發(fā)現(xiàn)函數(shù)返回的結(jié)果是number,所以result類(lèi)型也是number,因此我們只需要在參數(shù)位置加上類(lèi)型約束就可以了,TS在每個(gè)地方都有類(lèi)型檢查,是不是很牛逼??

?? 緊急通知: 翠花小姐姐來(lái)了
翠花小姐姐提了一個(gè)問(wèn)題:我怎么知道這類(lèi)型推導(dǎo)什么時(shí)候能推導(dǎo)成功,什么時(shí)候推導(dǎo)失敗呢?
?? 解答:
有個(gè)小技巧,當(dāng)我們看到變量或者函數(shù)的參數(shù)出現(xiàn)三個(gè)小點(diǎn),這三個(gè)點(diǎn)就是在提醒:你給我當(dāng)心點(diǎn),我確實(shí)做不到了,表示當(dāng)前沒(méi)有推導(dǎo)出來(lái)到底是什么類(lèi)型,可以用any類(lèi)型來(lái)表示,這時(shí)就需要手動(dòng)約束一下,

any:表示任意類(lèi)型,對(duì)該類(lèi)型,TS不進(jìn)行類(lèi)型檢查
看到這,我想大家已經(jīng)知道TS有非常強(qiáng)大的類(lèi)型檢查系統(tǒng),那么有個(gè)小問(wèn)題
?? 靈魂一問(wèn): 請(qǐng)問(wèn)手機(jī)號(hào)應(yīng)該定義成數(shù)字還是數(shù)字字符串?小伙伴們可以先思考一下再瞅一瞅
如何區(qū)分?jǐn)?shù)字字符串和數(shù)字,關(guān)鍵看怎么讀?如果按照數(shù)字的方式朗讀,則為數(shù)字,反之為字符串。

帥哥一聽(tīng),唉呀媽呀,再不走桃花運(yùn)被你耽擱了,趕緊拿出電話小本本,小心謹(jǐn)慎地生怕念錯(cuò)一個(gè)數(shù)字,131,5258,3720,平常我們都是這么念的,沒(méi)有人念一百三十一億五千二百五十八萬(wàn)三千七百二吧??,妹子要聽(tīng)了,滾~~,活該你單身!??
2. 基本類(lèi)型
注意是首字母是小寫(xiě)
number:數(shù)字,
let figure:number = 6;string:字符串
let user:string = "法醫(yī)";boolean:布爾值
let fake:boolean = false;array:數(shù)組
:number[]這種寫(xiě)法其實(shí)是語(yǔ)法糖,真正的寫(xiě)法是下面第二種,這兩種寫(xiě)法都可以約束數(shù)組的,看個(gè)人喜好,建議使用第一種,因?yàn)樵趓eact中尖括號(hào)表示組件,Array<number>可能會(huì)造成沖突let arr:number[] = [1,2,3];
let arr:Array<number> = [1,2,3];object:對(duì)象
object約束不是很常用,因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">object約束力不是很強(qiáng),它只能約束一個(gè)對(duì)象,卻不能約束對(duì)象里面的內(nèi)容,但是有時(shí)會(huì)用到//傳入一個(gè)對(duì)象,輸出value值
function getValues(obj:object) {
let vals = Object.values(obj);
console.log(vals); // 輸出 法醫(yī) 18
}
getValues({
name:"法醫(yī)",
age:18
})null和undefined
null和undefined需要重點(diǎn)說(shuō)一下,null和undefined是所有其他類(lèi)型的子類(lèi)型,它們可以賦值給其它類(lèi)型,但是又會(huì)發(fā)生隱患,下面方法調(diào)用都會(huì)報(bào)錯(cuò),由于約束了是string和number,但是值又是null和undefined,這種情況是我們不希望發(fā)生的。let str:string = null;
let nums:number = undefined;
//下面都會(huì)報(bào)錯(cuò),由于約束了是string和number,但是值又是null和undefined
str.toLocaleUpperCase();
nums.toString();?? 解決方案:
在
tsconfi.json配置文件中加上:"strictNullChecks": true之后可以獲得更加嚴(yán)格的空類(lèi)型檢查,null和undefined就不能賦值給其它的了
3. 其它常用類(lèi)型
聯(lián)合類(lèi)型:多種類(lèi)型任選其一
當(dāng)一個(gè)變量既可以為
字符串又可以為undefined的時(shí)候就可以使用聯(lián)合類(lèi)型,它可以配合使用類(lèi)型保護(hù)進(jìn)行判斷??
類(lèi)型保護(hù):當(dāng)對(duì)某個(gè)變量進(jìn)行類(lèi)型判斷之后,在判斷的語(yǔ)句中便可以確定它的確切類(lèi)型,tyoeof可以觸發(fā)類(lèi)型保護(hù),但是它只能觸發(fā)簡(jiǎn)單基本的類(lèi)型保護(hù),復(fù)雜類(lèi)型是沒(méi)有辦法觸發(fā)的let user:string | undefined;
if(typeof user === "string"){
//類(lèi)型保護(hù),當(dāng)進(jìn)入這個(gè)判斷,TS一定會(huì)知道,此時(shí)user一定是字符串
}viod類(lèi)型:通常用于約束函數(shù)返回值,表示該函數(shù)沒(méi)有任何返回
viod在Js也是有的,表示運(yùn)算一個(gè)表達(dá)式之后返回undefined,但在TS意思是不同的,通常用于約束函數(shù)返回值,表示該函數(shù)沒(méi)有任何返回function user():void{
console.log("法醫(yī)");
}當(dāng)然不約束也是可以的,因?yàn)闀?huì)
類(lèi)型推導(dǎo)出來(lái)
never類(lèi)型:通常用于約束函數(shù)返回值,表示該函數(shù)永遠(yuǎn)不可能結(jié)束
function thorwError(msg:string) {
throw new Error(msg)
}這個(gè)函數(shù)的
類(lèi)型推導(dǎo)是有問(wèn)題的,推導(dǎo)的類(lèi)型是viod,因?yàn)樗肋h(yuǎn)不會(huì)結(jié)束,類(lèi)型應(yīng)該是never而不是viod,所以需要手動(dòng)更改
function thorwError(msg:string):never {
throw new Error(msg)
}由于是永遠(yuǎn)不會(huì)結(jié)束,所以,下面的log函數(shù)無(wú)法執(zhí)行,無(wú)法訪問(wèn)代碼

還有一種情況也是永遠(yuǎn)不會(huì)結(jié)束,需要手動(dòng)約束

字面量類(lèi)型:使用一個(gè)
值進(jìn)行約束,而不是類(lèi)型約束//表示從此以后,變量name只能是 “法醫(yī)”,別的就會(huì)報(bào)錯(cuò)
let name:"法醫(yī)";
一般我們可以用字面量類(lèi)型對(duì)性別或者對(duì)象中的屬性進(jìn)行約束:
//對(duì)gender 變量進(jìn)行約束,只能是男或女,其它不行
let gender :"男" | "女";
//對(duì)users對(duì)象中的name和age屬性分別約束為字符串和數(shù)字,下次給users賦值的時(shí)候,只能包含name和age
let users:{
name:string
age:number
}元組類(lèi)型(Tuple):用的不多,了解一下就可以了,表示固定長(zhǎng)度的數(shù)組,并且數(shù)組中的每一項(xiàng)類(lèi)型確定
//定義了一個(gè)變量為tupleType的數(shù)組,這個(gè)數(shù)組只能有兩項(xiàng),并且第一個(gè)必須為字符串,第二個(gè)必須為數(shù)字
let tupleType:[string,number];
//第一項(xiàng)必須為字符串,第二項(xiàng)必須為數(shù)字,只能有兩項(xiàng),否則報(bào)錯(cuò)
tupleType = ["法醫(yī)",5];any類(lèi)型:any類(lèi)型可以繞過(guò)類(lèi)型檢查,因此any類(lèi)型可以賦值給任意類(lèi)型,但肯定是有隱患的,因?yàn)樗鼰o(wú)法使用TS提供的保護(hù)機(jī)制,所以不建議隨意的使用
any類(lèi)型,為了解決any帶來(lái)的問(wèn)題,TS3.0引入了unknown類(lèi)型
4. 類(lèi)型別名
給已知的類(lèi)型起個(gè)新的名字,防止重復(fù)書(shū)寫(xiě)一些代碼
type Gender = "男" | "女";
type user = {
name:string
age:number
gender:Gender
}
function getUser(g:Gender) {
//...
}
5. 函數(shù)的相關(guān)約束
函數(shù)重載
先看一個(gè)函數(shù)combine,功能是如果傳遞兩個(gè)數(shù)字作為參數(shù)的時(shí)候相乘,傳遞兩個(gè)字符串的時(shí)候相加,不相同都會(huì)報(bào)錯(cuò)。
function combine(a:number | string,b:number | string):number | string {
if(typeof a === "number" && typeof b === "number"){
return a * b;
}
else if(typeof a === "string" && typeof b === "string"){
return a + b;
}
throw new Error("a和b必須是相同的類(lèi)型")
}
函數(shù)本身沒(méi)有什么問(wèn)題,問(wèn)題就發(fā)生在函數(shù)調(diào)用的過(guò)程中,當(dāng)我們代碼寫(xiě)多了以后,我們也許會(huì)失誤傳遞不同的類(lèi)型作為參數(shù),更可怕的是如果參數(shù)是函數(shù)的返回結(jié)果,那就更蒙了,因此,在函數(shù)的調(diào)用過(guò)程中最好告訴調(diào)用函數(shù),要么都是數(shù)字類(lèi)型,要么都是字符串類(lèi)型。

從邏輯上來(lái)說(shuō),都是數(shù)字的話返回的結(jié)果就是數(shù)字類(lèi)型,都是字符串的話返回的結(jié)果就是字符串類(lèi)型,然而result的類(lèi)型是string | number,上圖可以清晰看到,這種情況,后面就沒(méi)有辦法使用result變量了,因?yàn)槊髅髦蓝际菙?shù)字返回的結(jié)果一定是數(shù)字類(lèi)型,都是字符串返回的一定是字符串類(lèi)型。意味著代碼提示中不會(huì)出現(xiàn)所有數(shù)字擁有的方法或者所有字符串所擁有的方法,只會(huì)提示數(shù)字和字符串共同擁有的方法——toString和valueOf如下圖:

?? 解決方案:
加上下面兩句代碼,這兩句代碼相當(dāng)于告訴 TS combine函數(shù)只能有兩種情況,一種是兩個(gè)數(shù)字返回?cái)?shù)字,另一種是兩個(gè)字符串返回字符串,這兩句代碼就叫函數(shù)重載。
??
函數(shù)重載:在函數(shù)實(shí)現(xiàn)之前,對(duì)函數(shù)調(diào)用的多種情況進(jìn)行聲明。
//加上這兩句代碼
/**
* 得到a * b的結(jié)果
* @param a
* @param b
*/
function combine(a:number,b:number):number;
/**
* 得到a + b的結(jié)果
* @param a
* @param b
*/
function combine(a:string,b:string):string;
function combine(a:number | string,b:number | string):number | string {
if(typeof a === "number" && typeof b === "number"){
return a * b;
}
else if(typeof a === "string" && typeof b === "string"){
return a + b;
}
throw new Error("a和b必須是相同的類(lèi)型")
}
let result = combine("b","n");
使用函數(shù)重載之后,當(dāng)調(diào)用函數(shù)的時(shí)候只能傳兩個(gè)數(shù)字或者兩個(gè)字符串,否則會(huì)報(bào)錯(cuò)。
可選參數(shù)
??
可選參數(shù):可以在某些參數(shù)名后面加上?號(hào),表示該參數(shù)可以不用傳遞。可選參數(shù)必須要在參數(shù)列表的末尾

當(dāng)形參為三個(gè),調(diào)用函數(shù)卻傳了兩個(gè),就會(huì)報(bào)錯(cuò),TS是很?chē)?yán)格的,不允許參數(shù)數(shù)量不匹配。假設(shè)第三個(gè)參數(shù)可以不傳遞,加個(gè)?號(hào)表示是可選參數(shù)

?? 結(jié)束語(yǔ)
寫(xiě)完又是深夜了,TS基礎(chǔ)之基本類(lèi)型檢查就寫(xiě)完了,本來(lái)想著把TS基礎(chǔ)部分整理成萬(wàn)字文再分享給大家的,但又覺(jué)得篇幅過(guò)長(zhǎng)閱讀不便,那就慢慢更新吧,有任何疑問(wèn)可以留言,小伙伴們點(diǎn)個(gè)贊 ?? 關(guān)注?再走吧!~ ??,我會(huì)更有動(dòng)力的,晚安!??
