【D1n910前端學(xué)習(xí)筆記】TypeScript完全解讀(2/26) 02-基礎(chǔ)類(lèi)型
? ? ?正常操作,正常分析,大家好,我是D1n910

上期內(nèi)容是

相比起來(lái),這期會(huì)顯得有些“無(wú)聊”,啊哈哈,因?yàn)槲抑白詫W(xué)過(guò)大部分的內(nèi)容,所以基礎(chǔ)類(lèi)型的我已經(jīng)過(guò)過(guò)了,希望Lison老師能給我一些不一樣的內(nèi)容~
現(xiàn)在開(kāi)始

TypeScript完全解讀(2/26)基礎(chǔ)類(lèi)型
0 核心內(nèi)容
布爾值
數(shù)值
字符串
數(shù)組
元組
枚舉值
any
void
null和undefined
never
object
類(lèi)型斷言
0.1 預(yù)備工作
在上一節(jié)課的項(xiàng)目里,`src`下新建一個(gè)文件夾`example`,以后上課的例子,一般都放到`example`里

這節(jié)課先創(chuàng)建一個(gè)`base-type.ts`文件

我們通過(guò)VScode來(lái)開(kāi)發(fā)ts項(xiàng)目,可以下載一些插件,比如 `tslint`,這樣可以有很好的代碼提示

我們把項(xiàng)目跑起來(lái)(`npm start`),當(dāng)我們需要看到值或者結(jié)果時(shí),我們可以在瀏覽器的控制臺(tái)查看結(jié)果

正式開(kāi)始——
1、布爾類(lèi)型(boolean)
布爾類(lèi)型只有兩種值(true/false)
在ts中聲明布爾值如下

這個(gè)有什么作用呢?
比如我們把一個(gè)非布爾類(lèi)型的值賦值給剛剛定義的布爾類(lèi)型的變量,會(huì)有提示有問(wèn)題,且會(huì)告訴你具體有什么問(wèn)題。
這邊就會(huì)提示不能將類(lèi)型“123”分配給類(lèi)型“boolean”(這邊“134”這么又會(huì)是一個(gè)類(lèi)型呢,后 面會(huì)說(shuō)這種類(lèi)型)

我們還可以這么聲明變量

2、數(shù)值類(lèi)型(number)
數(shù)值類(lèi)型的聲明是 `number`?

ts支持es6的新增的二進(jìn)制和八進(jìn)制的字面量進(jìn)行賦值

3、字符串類(lèi)型(string)
支持普通的字符串賦值,也支持模版字符串

這里的打印方法想要被執(zhí)行,我們可以在入口文件`index.ts`中引入`base-type.ts`
import './example/base-type.ts'

保存后在控制臺(tái)可以看到對(duì)應(yīng)輸出

4、數(shù)組類(lèi)型
數(shù)組類(lèi)型的定義有兩種寫(xiě)法
以數(shù)值數(shù)組類(lèi)型(例子 [1, 2, 3])
4.1、寫(xiě)法1
`let arr:number[]`
我們可以這么賦值
arr = [1, 2, 3] // 正確
如果我們這么賦值:
arr = [1, 'a', 2] // 報(bào)送類(lèi)型錯(cuò)誤
4.2、寫(xiě)法2
let arr2:Array<number> // 意思是指定一個(gè)數(shù)組類(lèi)型,然后其中是number元素
4.3、聯(lián)合類(lèi)型:數(shù)組中寫(xiě)多種類(lèi)型
我們的數(shù)組不一定就存儲(chǔ)一種類(lèi)型,這時(shí)候,我們可以使用聯(lián)合類(lèi)型
比如我們指定既可以是string又可以是number類(lèi)型
let arr3:(string | number)[]
通過(guò)這樣的方法,我們可以這么賦值
arr3 = [1, 'a']
記住需要加入括號(hào),如果不加入括號(hào)的話(huà),即為let arr3:string?|?number[],ts會(huì)理解為既可以是arr3既可以是string類(lèi)型,又可以是數(shù)值數(shù)組類(lèi)型。
本小節(jié)涉及代碼

5、元組類(lèi)型
大家可能聽(tīng)得不多元組。
他在ts的作用類(lèi)似數(shù)組,但是是數(shù)組的拓展。和數(shù)組的區(qū)別在于。
數(shù)組:指定了元素的類(lèi)型,就可以隨便往里添加任意數(shù)量符合元素類(lèi)型的值
元組:區(qū)別在于,固定長(zhǎng)度,固定類(lèi)型。
這里我們簡(jiǎn)單定義一個(gè)元祖類(lèi)型
let tuple: [string, number, boolean]
我們這么定義后,必須要按照順序、類(lèi)型來(lái)賦值
tuple = ['a', 2, false] // 正確
// 少了不行
tuple = ['a', 1] // Property '2' is missing in type '[string, number]' but required in type '[string, number, boolean]'.
// 不對(duì)應(yīng)類(lèi)型的不行
tuple = ['a', 1, 2]?// 不能將類(lèi)型“number”分配給類(lèi)型“boolean”?
// 多了類(lèi)型的不行
tuple = ['a', 1, false, 2]?//?不能將類(lèi)型“[string, number, false, number]”分配給類(lèi)型“[string, number, boolean]”。?屬性“l(fā)ength”的類(lèi)型不兼容。? ?不能將類(lèi)型“4”分配給類(lèi)型“3”。
// 可以和數(shù)組類(lèi)型一樣指定下標(biāo)賦值
tuple[2] = true // 正確
// 指定下標(biāo)賦值也要正確對(duì)應(yīng)的類(lèi)型
tuple[2] = 1 //?不能將類(lèi)型“1”分配給類(lèi)型“boolean”
本小節(jié)涉及代碼

6、枚舉類(lèi)型
這個(gè)如果我們有接觸過(guò)C++類(lèi)型的語(yǔ)言,那么會(huì)比較熟悉。我們會(huì)定義一些名字,然后每一個(gè)名字對(duì)應(yīng)一個(gè)索引值。
在ts中,也加入了枚舉。
使用 `enum` 來(lái)定義枚舉。
假設(shè)我們定義了一組權(quán)限值,比如“超級(jí)管理員”、“管理員”、“用戶(hù)”
下面就是基礎(chǔ)的枚舉值的名字,我們習(xí)慣于把枚舉值的變量名首字母大寫(xiě)
enum Roles {
????SUPER_ADMIN,
????ADMIN,
????USER
}
我們可以直接這么使用
console.log(Roles.SUPER_ADMIN) //?0
console.log(Roles.ADMIN) //?1
console.log(Roles.USER) // 2

能看到打印出序列號(hào),這序列號(hào)是自動(dòng)的。
這個(gè)枚舉類(lèi)型有什么作用呢?
舉一個(gè)簡(jiǎn)單的場(chǎng)景:
我們需要根據(jù)后端返回的用戶(hù)類(lèi)型執(zhí)行對(duì)應(yīng)的代碼,比如后端返回用戶(hù)類(lèi)型types的值為0,代表超級(jí)管理員,我們會(huì)這么寫(xiě)代碼
if ( types === 0?) {
????// 執(zhí)行一些代碼
}
// types === 0 不是很明顯知道這代表了什么,但是如果用上了枚舉類(lèi)型,那么我們可以這么做
if (?types === Roles.SUPER_ADMIN?) {
????// 執(zhí)行一些代碼
}
// 這樣看起來(lái)就好很多了
咱們的序列號(hào)可以是自動(dòng)的,也可以是自定義的
enum Roles {
????SUPER_ADMIN = 1,
????ADMIN = 3,
????USER
}
這邊我們進(jìn)行打印以后會(huì)發(fā)現(xiàn)得到的結(jié)果,SUPER_ADMIN 和 ADMIN都是對(duì)應(yīng)的值,而USER則是在ADMIN上自動(dòng)加一位。

我們可以通過(guò)枚舉的名稱(chēng)找到索引值,也可以通過(guò)枚舉的索引值找到對(duì)應(yīng)的名稱(chēng)

注意??:ts是一個(gè)翻譯機(jī),那么這個(gè)枚舉類(lèi)型翻譯成js代碼是這么實(shí)現(xiàn)的呢?
以
enum Roles {
????SUPER_ADMIN,
????ADMIN = 4,
????USER
}
為例子,在typesscript翻譯后,會(huì)變成
var?Roles;
(function?(Roles)?{
????Roles[Roles["SUPER_ADMIN"]?=?0]?=?"SUPER_ADMIN";
????Roles[Roles["ADMIN"]?=?4]?=?"ADMIN";
????Roles[Roles["USER"]?=?5]?=?"USER";
})(Roles?||?(Roles?=?{}));
// 我們可以用這個(gè)typescript的線(xiàn)上編譯器 http://www.typescriptlang.org/play/index.html 來(lái)查看翻譯后的內(nèi)容
// 這邊運(yùn)用到了一個(gè)小知識(shí)點(diǎn)是,對(duì)象屬性賦值操作的表達(dá)式其實(shí)是個(gè)隱藏了會(huì)返回賦值的內(nèi)容的情況

// 在這里的設(shè)計(jì)非常巧妙,即設(shè)置了屬性對(duì)應(yīng)序號(hào),又設(shè)置了序號(hào)對(duì)應(yīng)屬性;所以我們可以經(jīng)??纯磘ypescript的大佬這么翻譯的,學(xué)學(xué)大佬的代碼
7、any類(lèi)型
javascipt是非常靈活的,我們的數(shù)據(jù)或者一些邏輯可能要運(yùn)行的時(shí)候才能確定類(lèi)型,寫(xiě)代碼的時(shí)候是不知道類(lèi)型的,那么這時(shí)候我們就需要指定我們的類(lèi)型為any。
我們賦任意類(lèi)型的值。

對(duì)于數(shù)組類(lèi)型的元素也可以是any

這么方便的類(lèi)型,我們是不是在什么地方都用any呢?
那這樣的話(huà),我們就沒(méi)有用ts的意義了。
any是能不用就不用。
* 如果不給變量指定類(lèi)型,會(huì)隱式地指定為any類(lèi)型

8、void類(lèi)型
void和any類(lèi)型相反,void的意思就是什么類(lèi)型也不是
一般我們常用來(lái)定義一個(gè)不會(huì)返回任何值的函數(shù)

具體函數(shù)相關(guān)的內(nèi)容,會(huì)在后面講函數(shù)的時(shí)候涉及。
在JavaScript中,一個(gè)函數(shù)如果沒(méi)有指定返回內(nèi)容,那么默認(rèn)會(huì)返回undefined
那為什么這邊可以定義咱們這個(gè)函數(shù)返回值類(lèi)型為void呢?
因?yàn)樵趖s中,void類(lèi)型可以被賦給undefined以及null

這里我們發(fā)現(xiàn)賦值null給void類(lèi)型的時(shí)候,有報(bào)錯(cuò)`不能將類(lèi)型“null”分配給類(lèi)型“void”`
原因是我們生成的ts的配置文件`tsconfig.json`中,我們直接生成后,沒(méi)有對(duì)里面的內(nèi)容做修改。我們?cè)诤竺娴捻?xiàng)目配置一塊會(huì)詳細(xì)地講項(xiàng)目配置內(nèi)容,現(xiàn)在簡(jiǎn)單看看。

這些選項(xiàng)是用來(lái)控制【嚴(yán)格檢查代碼】的。
比如`strictNullChecks`就是涉及到了我們剛剛的報(bào)錯(cuò)問(wèn)題。我們把這個(gè)配置項(xiàng)設(shè)定為false,即關(guān)掉。

就可以看到不會(huì)有報(bào)錯(cuò)了。

* 注意,我們修改了`tsconfig.json`,需要重新npm start
9、null和undefined類(lèi)型
ts定義undefined類(lèi)型后
let u: undefined
這個(gè)u變量就只能被賦給undefined或者null的值了

同樣的,ts定義null類(lèi)型后
let u: null
這個(gè)u變量就只能被賦給undefined或者null的值了

undefined、null能相互賦值的原因是因?yàn)楸旧硭鼈兙褪穷?lèi)型的子類(lèi)型

但是如果我們把剛剛`strictNullChecks`選項(xiàng)打開(kāi)

就會(huì)代碼嚴(yán)格,報(bào)錯(cuò)提示只能賦值給對(duì)應(yīng)類(lèi)型

一般來(lái)說(shuō)我們?yōu)榱俗尨a更規(guī)范,會(huì)把嚴(yán)格模式都打開(kāi)。
10、never類(lèi)型
表示的是永遠(yuǎn)不存在的值的類(lèi)型
【拋錯(cuò)誤情況】
比如一個(gè)函數(shù)執(zhí)行后會(huì)一定會(huì)拋出錯(cuò)誤,那么它永遠(yuǎn)不會(huì)有返回值

【死循環(huán),永遠(yuǎn)沒(méi)有返回值情況】

never類(lèi)型的值是任意類(lèi)型的子類(lèi)型 —— never類(lèi)型的值可以賦值給任意類(lèi)型
沒(méi)有任意類(lèi)型的值是never類(lèi)型的子類(lèi)型——除了never 類(lèi)型的值,其他類(lèi)型都不能賦給never類(lèi)型。
這里我們通過(guò)使用必包創(chuàng)建一個(gè)never類(lèi)型的變量,印證了我們的規(guī)則。

11、object類(lèi)型
object類(lèi)型就是對(duì)象類(lèi)型,在js中和其他基礎(chǔ)類(lèi)型不一樣,其他的一些數(shù)值類(lèi)型、字符串類(lèi)型是直接存值,而object是存的是內(nèi)存中地址的引用。
ts中可以指定一個(gè)值的類(lèi)型為對(duì)象類(lèi)型

12、類(lèi)型斷言
有時(shí)候ts并沒(méi)有了解一個(gè)值的真實(shí)類(lèi)型,我們希望這個(gè)類(lèi)型檢查由我們自己進(jìn)行,我們自己知道這個(gè)值是什么類(lèi)型。那這個(gè)類(lèi)型斷言有點(diǎn)像類(lèi)型轉(zhuǎn)換,它可以根據(jù)某個(gè)值強(qiáng)行轉(zhuǎn)換為我們需要的值。
比如我們可能傳入的值是數(shù)值類(lèi)型的,也可能是字符串類(lèi)型的,而我們要返回傳入值的字符長(zhǎng)度,寫(xiě)下面的一個(gè)方法
const getLength = target => {
? ?if (target.length || target.length === 0) {
? ? ? ?return target.length
? ?} else {
? ? ? ?return target.toString().length
? ?}
}
在ts中,如何進(jìn)行類(lèi)型定義呢?
首先,我們的第一行,定義傳參是聯(lián)合類(lèi)型,可能是string也可能是number,返回的類(lèi)型當(dāng)然是number
但是這會(huì)有一個(gè)問(wèn)題,傳參能調(diào)用的方法,必須是聯(lián)合類(lèi)型的交集方法,即要都有才能使用。

這邊我們知道,其實(shí)我們的函數(shù)邏輯是沒(méi)錯(cuò)的,但是ts有類(lèi)型判斷,所以會(huì)這樣。
我們可以通過(guò)類(lèi)型斷言解決,有兩種寫(xiě)法
(1)尖括號(hào)+括弧形式

(1)變量名 as 類(lèi)型形式

這兩種類(lèi)型斷言都可以
最終添加了類(lèi)型斷言的如下所示

我們發(fā)現(xiàn),每次這邊用到string方法的target都要定義一下,很麻煩,后面我們會(huì)學(xué)到高階類(lèi)型自定義保護(hù),到那個(gè)時(shí)候,只需要做一次類(lèi)型保護(hù)即可。
* 如果我們使用jsx的寫(xiě)法的話(huà),我們只能使用 as 的方法
?

完畢
腰酸背痛……看視頻學(xué)基礎(chǔ)太痛苦了……困死……
本小節(jié)倉(cāng)庫(kù)地址
https://github.com/D1N910/ts-learning/tree/master/02

恭喜你獲得稱(chēng)號(hào)
了解typescript基礎(chǔ)類(lèi)型的勇士
你的學(xué)習(xí)進(jìn)度(2/26)
▇▇ ▇▇?▇▇ ▇▇ ▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇?▇▇ ▇▇

?聲明
本系列內(nèi)容是D1n910通過(guò)學(xué)習(xí)Lison老師的TypeScript完全解讀(26課時(shí))整理的文字筆記,如果看完后覺(jué)得有收獲,抑或想要直接支持,抑或想要直接視頻原版內(nèi)容,請(qǐng)直接到https://segmentfault.com/ls/1650000018455856?r=bPXT7X。

雖然本系列是筆記,但是也有D1n910的心血所在,請(qǐng)勿在未告知D1n910及獲得D1n910允許的情況下直接轉(zhuǎn)載本筆記——如果您是基于筆記又生成您自己的筆記,這是一點(diǎn)問(wèn)題都沒(méi)有的~