【TypeScript 30】Day 4：陣列型別
Published: 2022-11-25 05:00:33

前幾天討論完了物件型別中的函式型別與基本物件型別後，接著來聊聊同樣隸屬於物件型別中的陣列型別吧!
> # 物件型別之陣列型別

## 陣列的推論

同樣的先從最基礎的型別推論開始看起，一個是全是 number 類型的陣列另一個則全都是 string 類型的陣列。

![圖一](https://cdn-images-1.medium.com/max/2112/1*79sJWOLCTMFxiNqwMvNnow.png)

陣列型別的註記方式也非常的直覺，在一個陣列中如果型別都相同會直接使用該陣列裡值的型別加上 " [] " ，直接告訴你這是一個 number 或 string 類型的陣列。

![圖二、陣列中的值全都是數字類型](https://cdn-images-1.medium.com/max/2000/1*m5c0ckHD9ZYzJUICGduC_w.png)

![圖三、陣列中的值全都是字串類型](https://cdn-images-1.medium.com/max/2000/1*-Jsfcy_yk6aIvaPqoaFlcg.png)

既然都已經將 number 、string 這兩個陣列推論完類型了，按造前面兩篇文章的邏輯來操作陣列中的元素看看會發生什麼事。

完全符合我們的預期，一旦 number 已經被定義為 number[]類型後接下來再想要修改、新增元素到陣列中一定要是 number 類型。

![圖四、Homogeneous Type Array — 同質性陣列](https://cdn-images-1.medium.com/max/2000/1*DOIGp0uKsi4QhOfz2mG7BQ.png)
>  混合類型陣列

再推論混合類型時，TS 很聰明使用了 union 來推論出陣列中所有的類型。

union 類似於 or 結合因此在這個陣列中可以存在的類型包括 ，string 、number、boolean以及一個 string 類型的物件。

![圖五、Heterogenous Type Array — 異質性陣列](https://cdn-images-1.medium.com/max/2000/1*EIzw9KZMX98eJ4xmed8dVA.png)
>  覆寫陣列中的物件

在 [Day2 — 物件型別](https://medium.com/@sickmi14798/typescript-30-day-2-%E7%89%A9%E4%BB%B6%E5%9E%8B%E5%88%A5-8960b933d761) 中提到複寫物件型別的雷點，接著我們就來測試看看在陣列裡的物件型別是不是有相同的問題，如下。

![圖六、三種不同的物件陣列](https://cdn-images-1.medium.com/max/2456/1*laaUNLpYcX7IrfoS_WeIPg.png)

下面一一列出推論出的型別。

![圖七、毫無懸念推論出的型別是 { name:string }[]](https://cdn-images-1.medium.com/max/2000/1*_bjcgi6VRPYMa6s2B_oUtQ.png)

![圖八、推論出 { name:string; isCrazy?:undefined } | { name: string ; isCrazy:boolean }[]](https://cdn-images-1.medium.com/max/2000/1*53mDjRzFxpQG5B_WFgTmIw.png)

![圖九、兩種型別使用 union 推論出 { name: string;} | { name: number;})[]](https://cdn-images-1.medium.com/max/2000/1*Q1Y9GScxhCnaUQ8epQvaYA.png)

圖七與圖九都在我們目前的理解範圍之內，圖八實際上要表示的意思其實就等同於

    ({ name: string; isCrazy?: boolean; }

不過這裡卻推論為，這裡與屬於後面文章的範疇，目前先擱著。

    const objArr2: (
    { name: string; isCrazy?: undefined;} | { name: string; isCrazy: boolean;})[]
>  重點：假設 SET 為陣列中所有元素的集合，**在大部分的情況之下 ( 好奇有哪種情況不會 ) **該陣列被 TypeScript 型別推論的結果為 ：

    (集合 SET 中所有 `union` 的結果) []

可能有點難理解那就來看看例子吧!!

圖十是兩種不同型別的函式所組成的陣列，依造上面公式預期得到 string 和 number類型的 function。

![圖十之一](https://cdn-images-1.medium.com/max/2456/1*aUGsCPQt7iUv1HP0PJWv_w.png)

推論出的類型是，與上述的公式相符。

    const set1: (((num1: number, num2: number) => number) | ((str1: string, str2: string) => string))[]

![圖十之二](https://cdn-images-1.medium.com/max/2000/1*ZWcwd-jCbd8cYW9-fJ2mAg.png)

那接下來檢查看看相同 I/O 的 function 吧

![圖十一之一、 I/O的類別都是 number](https://cdn-images-1.medium.com/max/2456/1*moX5tm-4nQwIbu0OEV9h2w.png)

因為結果都一樣，因此推論出了：

    const set2: ((num1: number, num2: number) => number)[]

![圖十一之二、 I/O的類別都是 number](https://cdn-images-1.medium.com/max/2000/1*mpfsli_OTQJtQ3DTqf7pww.png)

再來試試稍微更複雜一點的 array 包著 array 的三個例子：

 1. 第二層陣列中的元素只包含 string、number、boolean**此類的原始型別 ( Primitive Types)** 。

![圖十二之一](https://cdn-images-1.medium.com/max/2456/1*EdydEBwsNIK_njlXwTcWlw.png)

第一種情況很單純也很簡潔得到了

    const complexArr1: (string | number | boolean)[][]

![圖十二之二](https://cdn-images-1.medium.com/max/2000/1*7g6k_a7LX98Mac4BHtpjfQ.png)

2. 第二層陣列中的元素只除了**原始型別 ( Primitive Types)** ，還有**物件型別 (Object Types)**。

![圖十三之一](https://cdn-images-1.medium.com/max/2456/1*YSTaxllZ9KZmhwZ7Zh1thw.png)

如果陣列中有包含**物件型別**的話，則會將有物件型別的陣列(此範例是 [1, 2 , ’3’, { obj:1 } ] ) 另外歸類為**另一種型別的組合，**如下圖。

![圖十三之二](https://cdn-images-1.medium.com/max/2000/1*-fd3O0MsAnD45ul7lnWamg.png)

另外被分類的組合如下：

    (string | number | { obj: number;})[]

3. 第二層陣列中的元素只除了**原始型別 ( Primitive Types)** ，物件型別還有 nullable type。

![圖十四之一](https://cdn-images-1.medium.com/max/2456/1*gRHrSTJnDOwG4mcCrfyJnA.png)

和物件型別類似的概念，有包含 nullable type 的陣列也都被獨立出一個組合。

![圖十四之二](https://cdn-images-1.medium.com/max/2000/1*rtO5kR_fGYx5vOn1sjp00g.png)

## 陣列的註記

看完推論後接著就來看看註記吧，不過看完上面的推論過後，註記應該就沒有甚麼太大的問題了。

宣告一個空陣列，如果看過前兩篇文章的讀者應該不難猜到這裡的型別會被推論為 any []

    let emptyArr = []

![圖十五、沒有註記型別推論為 any (error 是 eslint 的 config)](https://cdn-images-1.medium.com/max/2000/1*j10fhcLlZTPxl8fZjialTw.png)

這是一種我們會想對陣列做積極註記的一種情況，而還有另一種情況你會想要對陣列做型別註記，那就是 — — 如果目前陣列的型別中，*沒有出現你需要的型別值*，你必須得對該陣列積極作型別備註。

什麼意思呢 ? 假設我們想讓下面這個陣列同時包含 string 和 nullable type 時

    const stringAndNull = [‘hello’, ‘angus’]

此時的 stringAndNull 此時的已經被推論為 string [] ，所以我們如果向以下程式碼推入 null，進入這個陣列一定會出錯。

![圖十六、只能插入 string 類型的值](https://cdn-images-1.medium.com/max/2000/1*Kx6dA-fOA4Dte2_G8Il6XQ.png)

因此我們就可以使用 union 來做積極註記，如此一來錯誤就被解決嚕!!

![圖十七、使用 union 做積極註記](https://cdn-images-1.medium.com/max/2000/1*Fs1kDmon2XCkYTLk9vrxuQ.png)

小結：這篇測試了比較多種的情況，經過親手測試後會對於錯誤印象更加深刻不過理所當然的花費的時間比較長一點。