--- tags: Node.js 直播班 - 2023 春季班 --- # TypeScript 暖身讀書會 - 下半場 * [3/17(五) 20:00 線上 ZOOM 網址](https://us06web.zoom.us/j/84593105307) ## 大綱 1. 補充 TypeScript 常見語法 2. 以此遊戲來延伸語法 [beginners-typescript-tutorial](https://github.com/total-typescript/beginners-typescript-tutorial),感謝 alphatero 推薦 3. [TypeScript 新手指南](https://willh.gitbook.io/typescript-tutorial/)、[Discord 同學討論](https://discord.com/channels/801807326054055996/1077558592401588234) ## interface 補充 - 可選屬性 * [React](https://github.com/lujakob/nestjs-realworld-example-app) - 放在各元件裡 * [angular](https://github.com/gothinkster/angular-realworld-example-app/tree/9e8c49514ee874e5e0bbfe53ffdba7d2fd0af36f/src/app/core/models) - 獨立 models 資料夾 * [React - Model](https://github.com/piotrwitek/react-redux-typescript-guide/blob/e0532ae099a1ddcce7cf263280e20714c7a53e72/playground/src/models/user.ts) - 放在 Model 裡面 * [Node](https://github.com/microsoft/TypeScript-Node-Starter/blob/master/src/models/User.ts) - 放在 model 裡 * [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template/tree/88b7440b3330324cf639d5cbeb5350994d020473/src/store/modules) - 放在各 modules * [vben-admin-thin-next](https://github.com/vbenjs/vben-admin-thin-next/tree/07c2567751c711541a4ff24af00f2cd018c18eab/src/api/sys/model) - models、[取出 user 表](https://github.com/vbenjs/vben-admin-thin-next/blob/07c2567751c711541a4ff24af00f2cd018c18eab/src/api/sys/user.ts) ``` // 範例一:出錯版本 interface Person { name: string; age: number; } let tom: Person = { name: 'Tom' }; // 範例二:可選屬性 interface Person { name: string; age?: number; } let tom: Person = { name: 'Tom' }; ``` ## 聯合型別 允許變數可以同時擁有不同的類型。可以更靈活地定義變數的類型,讓程式碼更容易閱讀和維護。 ``` // 定義一個可能是數字或字串的變數 let myVar: number | string; myVar = "hello"; // 正確 myVar = 123; // 正確 myVar = true; // 錯誤 // 印出 ID function printID(id: number | string): void { console.log("ID is: ", id); } printID(123); // ID is: 123 printID("abc"); // ID is: abc // 錯誤範例 function displayData(data: string | number): void { console.log(data.toFixed(2)); } displayData("hello"); // HELLO displayData(3.14159); // 3.14 ``` ## 型別推論 能夠根據變數的初始值自動推斷出該變數的型別,讓開發者在寫程式時更容易避免錯誤。 正確範例: ``` let weight = 60 // 體重(公斤) let height = 170 // 身高(公分) let bmi = weight / ((height/100) ** 2) // BMI 值 console.log(`BMI 值為 ${bmi}`) ``` 問題: ``` let numbers = [5, 2, 8, 1, 9] // 一個數字陣列 numbers.push("33"); console.log(`排序後的陣列:${numbers}`) ``` ``` let num = "123"; num = 456; ``` ``` function add(a, b) { return a + b; } add(1, "2"); ``` ## 泛型 泛型技術可將型別作為參數傳遞,提高程式碼可重用性及強型別語言的靈活性。應用於函式、類別、介面等元素,讓不同型別使用相同的代碼,減少重複代碼。 ### 兩個函式各自處理 ```=typescript function reverseNumbers(data: number[]): number[] { return data.reverse(); } function reverseString(data: string): string { return data.split("").reverse().join(""); } // 反轉一個數組 const numbers = [1, 2, 3, 4, 5]; console.log(reverseNumbers(numbers)); // [5, 4, 3, 2, 1] // 反轉一個字串 const str = "hello"; console.log(reverseString(str)); // 'olleh' ``` 改用泛型寫法後 ```=typescript function reverse<T>(data: T[]): T[] { return data.reverse(); } // 反轉一個數組 const numbers = [1, 2, 3, 4, 5]; console.log(reverse<number>(numbers)); // [5, 4, 3, 2, 1] // 反轉一個字串 const str = "hello"; console.log(reverse<string>(str.split(""))); // ['o', 'l', 'l', 'e', 'h'] ``` **範型約束 (generic constraint)**,可限制他代入的參數型別 ``` function reverse<T extends string | number>(data: T[]): T[] { return data.reverse(); } ``` **使用泛型定義兩個參數**,分別為 T 和 U,並返回一個 Tuple 類型的陣列,其中第一個元素為 T 型別的值,第二個元素為 U 型別的值: ```=typescript function makeTuple<T, U>(value1: T, value2: U): [T, U] { return [value1, value2]; } const tuple = makeTuple("hello", 123); // tuple 的型別為 [string, number],值為 ["hello", 123] ``` 限制 T 與 U 只支援數字和字串型別: ```=typescript function concat<T extends string | number, U extends string | number>(a: T, b: U): string { return `${a}${b}`; } console.log(concat("hello", "world")); // helloworld console.log(concat(1, 2)); // 12 ``` **async 需定義回傳的內容是 Promise 格式**,而這個 Promise 的泛型類型就是由最右邊的 <Post> 定義的。 在定義 async 函式時,並不需要在括號中定義泛型類型,因為 TypeScript 會根據函式中的 await 表達式自動推斷返回的 Promise 的泛型類型。而最右邊的 <Post> 是為了明確告訴 TypeScript 該 Promise 的泛型類型,可以提高程式碼可讀性。 ```=typescript interface Post { id: number; title: string; body: string; } export const getPostItem = async (): Promise<Post> => { const data = await fetch("https://swapi.dev/api/people/1").then((res) => { return res.json(); }); return data; }; ```