---
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;
};
```