# TypeScript - 陣列的型別 在 TypeScript 中,可以使用多種方式來定義陣列的型別。 ## 使用型別後綴法 Type Suffix Syntax:「型別 + 方括號」 在變數名稱後面加上 `[]`,表示這個變數是一個陣列,裡面包含的元素都是同一個型別。 ```typescript let numbers: number[] = [1, 2, 3, 4, 5] let names: string[] = ['Anna', 'Bob', 'Cathy'] ``` ## 使用陣列泛型 Array Generic 我們也可以使用陣列泛型(Array Generic) `Array<ElementType>` 來表示陣列,其中 `ElementType` 是你想要的陣列元素型別。: ```typescript let numbers: Array<number> = [1, 2, 3, 4, 5] let names: Array<string> = ['Anna', 'Bob', 'Cathy'] ``` > 泛型(Generics)是指在定義函式、介面或類別的時候,不預先指定具體的型別,而在使用的時候再指定型別的一種特性。 泛型允許你在**多個型別之間共享相同的結構**,使得程式碼更具可複用性。 在這種表示法中,我們可以將其他型別放入尖括號 `<>` 中,例如基本型別、自定義型別或介面。 ### 對陣列中的元素進行型別檢查 如果嘗試將不符合指定型別的值添加到陣列中,可以看到 TypeScript 會報錯: ```typescript! let numbers: number[] = [1, 2, 3, 4, 5] numbers.push('6') // index.ts:2:14 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. ``` ## 使用介面表示陣列 ```typescript! interface NumberArray { [index: number]: number; } let numbers: NumberArray = [1, 2, 3, 4, 5] ``` 在這個例子中,我們定義了一個 `NumberArray` 介面,它表示只要索引(index)的型別是 number 時,那麼值的型別就必須是 `number`。 雖然介面也可以用來表示陣列,但通常我們會直接採用更簡單的「型別+括號」方式來表示陣列: ```typescript! let numbers: number[] = [1, 2, 3, 4, 5] ``` 那什麼時候才會用到介面來表示陣列呢? 當我們需要描述**具有多個屬性和方法的複雜數據結構**時,用介面來表示陣列反而會讓數據組織和結構更清晰易讀。 比方說,我們常用它來表示「類陣列物件」。 ## 類陣列物件 Array-like Object 「類陣列物件」並不是陣列型別,而是指具有某些類似陣列特性的物件。它可以向陣列一樣**使用索引存取元素**,並且**具有 length 屬性**。 ### 類陣列物件:`arguments` 比如在 Javascript 中, `arguments` 是一個類陣列物件,因此不能使用一般的陣列方式來描述,需使用介面來描述: ```typescript // 使用型別+方括號表示 --> 報錯 function sum() { let args: number[] = arguments; } // Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more. ``` ```typescript // 使用介面表示 --> 正確 function sum() { let args: { [index: number]: number; length: number; callee: Function; } = arguments; } ``` ### 內建介面 - `IArguments` `IArguments` 是 TypeScript 的[內建介面](https://willh.gitbook.io/typescript-tutorial/basics/built-in-objects),已經定義好了型別,用於描述類陣列物件(Array-like Object),特別是用於描述 JavaScript 函數中的 `arguments` 類陣列物件。 它實際上就是: ```typescript interface IArguments { [index: number]: any; length: number; callee: Function; caller: Function; } ``` `IArguments` 介面約束了: - 索引的型別是數字時,值的型別是 `any` - 需有`length` 、 `callee`、`caller` 屬性 ### 其他常見的類陣列物件 除了 `IArguments` 之外其他常見的類陣列物件也有對應的介面: #### 1. `NodeList` 使用 `document.querySelectorAll` 或其他類似方法選取 DOM 元素時,會返回一個 `NodeList` 類陣列物件。它表示一組節點(Node)。 ```javascript const nodeList = document.querySelectorAll("div"); ``` #### 2. `HTMLCollection` 使用 `document.getElementsByClassName`、`document.getElementsByTagName` 等方法選取 DOM 元素時,會返回一個 `HTMLCollection` 類陣列物件。它表示一組 HTML 元素。 ```javascript const htmlCollection = document.getElementsByClassName("some-class"); ``` #### 類陣列物件都的共同特點 - 具有數字索引 - 具有 `length` 屬性 - 可以像陣列一樣遍歷,但並非真正的陣列 ## 任意型別 `any` 在陣列中的應用 常見的做法是用任意型別 `any` 來表示陣列中的元素可以是任何型別: ```typescript const mixedArray: any[] = [1, 'hello', true, { name: 'John' }, [3, 4, 5]] // 可以加入任何型別的元素 mixedArray.push(18) mixedArray.push('world') mixedArray.push({ age: 30 }) ``` ## 混合型別的陣列 如果陣列中的元素有不同的型別,我們可以使用聯合型別(Union Types)來表示這種情況: ```typescript let mixedArray: (number | string)[] = [1, "two", 3, "four"]; ``` ## Readonly 陣列 你可以使用 `ReadonlyArray<ElementType>` 來表示唯讀的陣列: ```typescript let readOnlyNumbers: ReadonlyArray<number> = [1, 2, 3]; ``` ## 在介面中使用陣列 你可以在介面中定義一個陣列的型別,然後在物件中使用該型別: ```typescript interface Data { values: number[]; names: string[]; } let data: Data = { values: [1, 2, 3], names: ["Alice", "Bob"] }; ``` ## Ref - [TypeScript 新手指南 (gitbook.io)](https://willh.gitbook.io/typescript-tutorial/) - [從零開始學 TypeScript 計畫](http://anna-yufeng.com/)