# 🏅 Day 11 - 什麼是泛型? ## 回顧之前陣列設定型別的方式 例如: 1. `number[]` 表示一個數字型別陣列 2. `string[]` 表示一個字串型別的陣列。 ```=tsx let numbers: number[] = [1, 2, 3]; let strings: string[] = ["hello", "world"]; ``` 除此之外,還有哪些定義方式呢? ## 陣列泛型(Array Generic) 此時也可以使用陣列泛型 `Array<元素型別>`,來達成一樣的效果: ```=tsx let numbers: Array<number> = [1, 2, 3]; let strings: Array<string> = ["hello", "world"]; ``` 這兩種方式都有符合一樣的效果,下方我們再寫個範例,主要是提供一個字串陣列,並單純回傳這個字串陣列,兩個效果也是一樣的,只是格式不同而已,一個是 **`Array<string>`** 另一個是 **`string[]`**。 ### 範例一:**`Array<string>`**: ```tsx function processStringArray1(arg: Array<string>): Array<string> { return arg; } let stringArray1: Array<string> = ["apple", "banana", "cherry"]; processStringArray1(stringArray1); // 輸出: ["apple", "banana", "cherry"] ``` ### 範例二:**`string[]`**: ```tsx function processStringArray2(arg: string[]): string[] { return arg; } // 使用這個函式 let stringArray2: string[] = ["apple", "banana", "cherry"]; processStringArray2(stringArray2); // 輸出: ["apple", "banana", "cherry"] ``` ## 開始進入重頭戲,泛型(Generics)! 泛型(Generics)是一種在定義函式、介面或類別時,不先確定具體的型別,而是在實際使用時,再指定型別的特性。 ```=tsx // `T` 是型別參數(Type Parameter),可代進任意輸入的型別。 function hello<T>(data:T){ console.log(data) } hello<string>("Jack")//Jack,data 參數型別會被代入為 String hello<string>(123) //會出錯,型別錯誤 hello<number>(123)//123,data 參數型別會被代入為 number ``` 上面的範例,我在函式名稱 `hello` 後添加了 `<T>`,裡面的 `T` 是**型別參數(Type Parameter)**,可以用來代入任意型別。 這個 `T` 也可以叫做其它名字,例如 `U`,下面程式碼也具備相同功能 ```tsx= //型別參數改為 U function hello<U>(data:U){ console.log(data) } hello<string>("Jack")//Jack,data 參數型別會被代入為 String hello<string>(123) //會出錯,型別錯誤 hello<number>(123)//123,data 參數型別會被代入為 number ``` 通常你在看其它範例,約定俗成會用 `T` 當作型別參數的原因, 主因是 `T` 是 type(型別) 縮寫關係 ### 泛型函式 return 當然這個型別參數,也能應用在 `return` 上 ```=tsx // return 也用到了型別參數 function hello<T>(data:T): T{ return data; } hello<string>("Jack")//回傳 Jack hello<string>(123) //會出錯,型別錯誤 hello<number>(123)//回傳 123 ``` ### 可以有多個型別參數 ```tsx= function callFun<T, U>(e1: T, e2: U): [U, T] { return [e2, e1]; } // 推薦:可以使用型別推論寫法 const a = callFun("world", 123); console.log(a); // [123, "world"] // 也可以使用型別註釋 const b = callFun<string,number>("world", 123); console.log(b); // [123, "world"] // 故意出錯的型別註釋 const c = callFun<string,string>("world", 123); console.log(c); // [123, "world"] ``` ## 問題來了,如果是這樣呢? ```js= function processStringArray(strings: string[]): string[] { // ... 一些對字串陣列的操作 return strings; } function processNumberArray(numbers: number[]): number[] { // ... 一些對數字陣列的操作 return numbers; } ``` 看起來兩個函式有一個共通之處,那就是函式參數、return 的型別都一樣,有辦法透過泛型優化嗎? ### **重構為泛型函式** 我們可以將這些函式重構為一個泛型函式,能夠接受任何型別的陣列。泛型 **`T`** 代表陣列中的元素型別。 ```tsx function processArray<T>(arr: T[]): T[] { return arr; } let strAry = ["apple", "banana", "cherry"]; let processedStrings = processArray<string>(strAry); let numberAry = [1, 2, 3]; let processedNumbers = processArray<number>(numberAry); ``` 在這個重構後的範例中,**`processArray`** 函式使用泛型 **`T`** 來表示陣列元素的型別。當你呼叫這個函式時,可以明確指定這個型別,如 **`processArray<string>`** 或 **`processArray<number>`**。 這樣你就能夠用同一個函式來處理多種型別的陣列,藉此來提升代碼的簡潔性。 ## 泛型圖解 以此範例程式碼為例子,下方繪製幾張流程圖,幫助大家吸收更順利 🙌 ```=tsx function hello<T>(data:T): T{ return data; } hello<string>("Jack")//Jack,data 參數型別會被代入為 String hello<string>(123) //會出錯,型別錯誤 hello<number>(123)//123,data 參數型別會被代入為 number ``` ### 泛型函式生成 ![截圖_2024-01-20_下午9_47_57](https://hackmd.io/_uploads/B1OBe8tt6.png) ### 泛型執行步驟 ![截圖_2024-01-20_下午9_48_01](https://hackmd.io/_uploads/H1b8l8FtT.png) # 開發題 ## 題目一:建立泛型字串陣列 ### 函式名稱 `createGenericStringArray` ### 輸入 兩個字串 `str1` 和 `str2`。 ### 輸出 一個泛型陣列 `Array<string>`,包含 `str1` 和 `str2`。 ### 範例 輸入`"hello"` 和 `"world"`,函式回傳陣列為 `["hello", "world"]`。 ### 程式碼線索 ```tsx= function createGenericStringArray(str1: <設定型別>, str2: <設定型別>): <設定回傳型別> { return <回傳格式>; } // 使用這個函式 const stringArray = createGenericStringArray("hello", "world"); console.log(stringArray); // 輸出: ["hello", "world"] ``` ## **題目二:泛型函式** 練習泛型 `<T>` 用法 ### **函式名稱** **`identity`** ### **輸入** 一個型別參數 **`value`**。 ### **輸出** 直接回傳輸入的 **`value`**。 ### **範例** 輸入一個數字 **`5`**,函式回傳 **`5`**;輸入一個字串 **`"hello"`**,函式回傳 **`"hello"`**。 ### **程式碼線索** ```tsx= // 補上型別參數 function identity(value):? { return value; } // 使用這個函式 const number = identity(5); console.log(number); // 輸出: 5 const string = identity("hello"); console.log(string); // 輸出: "hello" ``` ## 題目三:元組元素交換 ### 函式名稱 **`swapElements`** ### 輸入 一個包含兩個不同型別元素的元組(Tuple),例如 **`["hello", 10]`**。 ### 輸出 元素位置交換後的新元組,例如 **`[10, "hello"]`**。 ### 範例 輸入元組 **`["hello", 10]`**,函式回傳的元組為 **`[10, "hello"]`**。 ### 程式碼線索 ```tsx= function swapElements(){ return ; } // 使用這個函式 const swappedTuple = swapElements(["hello", 10]); console.log(swappedTuple); // 輸出: [10, "hello"] ``` ## **題目四:使用泛型處理不同型別的陣列** ### **函式名稱** **`processArray`** ### **輸入** - 一個泛型陣列 **`array: Array<T>`**,其中 **`T`** 可以是 **`string`**、**`number`** 或 **`boolean`**。 - 一個泛型函式 **`process: (item: T) => T`**,用於對陣列中的每個元素進行處理。 ### **輸出** 一個經過處理的泛型陣列 **`Array<T>`**,包含經過函式 **`process`** 處理過的所有元素。 ### **範例** 1. 輸入字串陣列 **`["apple", "banana"]`** 和一個將每個字串轉為大寫的函式,函式回傳陣列為 **`["APPLE", "BANANA"]`**。 2. 輸入數字陣列 **`[1, 2, 3]`** 和一個將每個數字加倍的函式,函式回傳陣列為 **`[2, 4, 6]`**。 3. 輸入布林陣列 **`[true, false, true]`** 和一個將每個布林值取反的函式,函式回傳陣列為 **`[false, true, false]`**。 ### **模擬程式碼** ```tsx= function processArray(array, process){ return ; } // 使用這個函式 const processedStrings = processArray(["apple", "banana"], (s) => s.toUpperCase()); console.log(processedStrings); // 輸出: ["APPLE", "BANANA"] ``` ## 回報流程 將答案寫在 CodePen,並貼至底下回報就算完成了喔! 解答位置請參考下圖(需打開程式碼的部分觀看) ![](https://i.imgur.com/vftL5i0.png) <!-- 解答: --> 回報區 --- | Discord | CodePen / 答案 | |:-------------:|:----------------------------------------------------------------:| |洧杰|[Codepen](https://codepen.io/hexschool/pen/poYgYqW?editors=1010)| |hannahpun|[Codepen](https://codepen.io/hannahpun/pen/ZEPyRJp?editors=0011)| |LinaChen|[Codepen](https://codepen.io/LinaChen/pen/WNmOyZN)| |苡安|[Codepen](https://codepen.io/yi-an-yang/pen/bGZRjbE)| |精靈|[CodePen](https://codepen.io/justafairy/pen/vYPZaZB)| |m_m|[CodePen](https://codepen.io/minnn7716/pen/JjzWqQz)| |展誠|[CodePen](https://codepen.io/hedgehogkucc/pen/YzgQvVv?editors=1012)| |Amberhh | [codepen](https://codepen.io/Amberhh/pen/wvOexVq?editors=0011)| |77_0411| [CodePen](https://codepen.io/chung-chi/pen/dyrRqbY?editors=1011)| |Henry_Wu|[Codepen](https://codepen.io/hekman1122/pen/vYPZzPW?editors=0010)| |HsienLu|[CosePen](https://codepen.io/Hsienlu/pen/poYPwaK)| |clairechang|[Notion](https://claire-chang.notion.site/Day-11-ec326e552d4148b8abdec5b8790fbd93)| |hannahTW|[codepen](https://codepen.io/hangineer/pen/NWJgBEv?editors=1011)| |Lisa|[codepen](https://codepen.io/lisaha/pen/RwdgOpp?editors=1012)| |wendy_.li|[HACKMD](https://hackmd.io/PcmFgqZwRd-4Ep3-LgK5_Q)| |Bryan Chu|[CodePen](https://codepen.io/bryanchu10/pen/mdowYVK)| |jasperlu005|[Codepen](https://codepen.io/uzzakuyr-the-reactor/pen/KKEqLNK?editors=1011)| |deedee1215|[Codepen](https://codepen.io/diddy032/pen/gOERmmX)| |Mi|[Codepen](https://codepen.io/Mi-Jou-Hsieh/pen/NWJgmaz?editors=1011)| |yunhung|[Codepen](https://codepen.io/ahung888/pen/JjzyoeK?editors=0011)| |Kai|[Codepen](https://codepen.io/kaiyuncheng-the-styleful/pen/bGZrVWe?editors=0011)| |連小艾|[Codepen](https://codepen.io/bolaslien/pen/YzgxWyB?editors=0011)| |雙魚|[Codepen](https://codepen.io/emiarcak/pen/RwdZRxb?editors=0012)| |hiYifang|[HackMD](https://hackmd.io/@gPeowpvtQX2Om6AmD-s3xw/r1dPCijta)| |JC|[Codepen](https://codepen.io/jcsamoyed/pen/PoLjXqm?editors=0012)| |Alyce|[Codepen](https://codepen.io/alycehwy/pen/YzgQOZp)| |翰毅|[Codepen](https://codepen.io/yzuigtdw-the-animator/pen/LYajxpJ?editors=1111)| |YC|[HackMD](https://hackmd.io/SKoJd3EsTlitnjzCx4Rarg)| |皓皓|[HackMD](https://hackmd.io/@cutecat8110/ry93J23YT)| |erwin阿瀚|[CodePen](https://codepen.io/yohey03518/pen/vYPJpqJ?editors=1010) |Teddy|[CodePen](https://codepen.io/TaideLi/pen/RwdZMaO) |BonnieChan|[CodePen](https://codepen.io/Bonnie-chan-the-bold/pen/jOJLZpE?editors=0011) |wei|[codePen](https://codepen.io/jweeei/pen/bGZraNR?editors=1011)| |Starr|[codePen](https://codepen.io/StarrZhong/pen/qBvXzbY)| |wei|[codePen](https://codepen.io/jweeei/pen/bGZraNR?editors=1011)| |Otis|[codePen](https://codepen.io/humming74/pen/NWJaNeZ?editors=1012)| |shan13|[codePen](https://codepen.io/yishan13-tsai/pen/MWxEezE)| |rikku1756|[codePen](https://codepen.io/rikkubook/pen/zYbEPaR?editors=1111)| |銀光菇|[codePen](https://codepen.io/genesynthesis/pen/YzgEyza)| |薏慈|[CodePen](https://codepen.io/its_wang/pen/BabmoxB)| |神奇海螺|[CodePen](https://codepen.io/ksz54213/pen/eYXePgoL)| |Snorlax|[HackMD](https://hackmd.io/@snorlaxpock/r1IRG3iK6)| |leave3310|[HackMD](https://codepen.io/leave3310-the-looper/pen/BabVRZa?editors=0011)| |Tori|[HackMD](https://hackmd.io/OAdkiOH-S_WkD-LF6IONVA?view)| |我是泇吟|[Codepen](https://codepen.io/kljuqbxs/pen/rNEgqKv)|