---
# System prepended metadata

title: "\U0001F3C5 Day 19 - Utility Types"
tags: [TypeScript 30 天證書培訓營 - 2024]

---

# 🏅 Day 19 - Utility Types

TypeScript 提供了幾種工具型別(Utility Types)，以方便常見的型別轉換。這些工具型別在全域範圍內可用。


## Partial<Type>
**`Partial<Type>`** 會回傳一個新的型別，會將原型別`<Type>`中的所有屬性都設定為可選。

```tsx=
interface num {
  x: number;
  y: number;
}
 
type newNum = Partial<num>; 
// 會變成 { x?: number; y?: number; }

```
![截圖 2024-01-29 下午11.57.34](https://hackmd.io/_uploads/SyMbiHr5T.png)



### 待辦事項情境
有一個代表待辦事項的介面 **`Task`**，它包含了多個屬性，如 **`title`**（標題）和 **`dueDate`**（截止日期）。

如果想要實作一個**更新功能**，讓使用者可以只更新待辦事項的部分資訊，而不是必須提供所有資訊。

```tsx
// 定義待辦事項介面
interface Task {
  title: string;
  dueDate: Date;
}

// 函式允許更新待辦事項的部分資訊
function updateTask(task: Task, fieldsToUpdate: Partial<Task>) {
  return { ...task, ...fieldsToUpdate };
}

// 建立一個既有的待辦事項
const task1 = {
  title: "閱讀書籍",
  dueDate: new Date(2024, 1, 30), // 2024年2月30日
};

// 僅更新待辦事項的標題
const task2 = updateTask(task1, {
  title: "參加線上研討會",
});



```

**`Partial<Task>`** 允許建立一個只包含 **`Task`** 介面中某些屬性的物件，對於只更新待辦事項的部分資訊實用性就蠻大的。
    
這語法在第 15 天保哥的介紹影片中，[20 分鐘](https://youtu.be/SCLKlc6G0_k)處也有提及其優雅之處

## Readonly<Type>
**`Readonly<Type>`** 這個工具型別也會回傳一個新的型別，主要是將`Type` 的所有屬性都變成唯讀。

### 圖書館情境
介面 **`Book`**，它包含了幾個屬性，如 **`title`**（書名）和 **`author`**（作者）。一旦圖書被登記到系統中，假使不希望這些資訊被改變，就很適合這樣用：

```tsx
// 定義一個代表圖書的介面
interface Book {
  title: string;
  author: string;
}

// 使用 Readonly 將 Book 的所有屬性變成唯讀
type ImmutableBook = Readonly<Book>;

// 登記一本圖書
const book: ImmutableBook = {
  title: "深入淺出 TypeScript",
  author: "作者名稱",
};

// 修改書名或作者會導致錯誤
// book.title = "新書名"; // 這行會報錯，因為 title 是唯讀的

```
![截圖 2024-01-30 上午12.16.39](https://hackmd.io/_uploads/SypdkUS5p.png)



**`Readonly<Type>`** 也可以與 **`Partial<Type>`** 結合，使用來創建一個所有屬性都是唯讀且可選的型別。**適合用在只能初始化一次但部分屬性可能未被賦值的物件**，如下範例程式碼

```tsx=
const temporaryBook: Readonly<Partial<Book>> = { title: "暫定書名" };

// temporaryBook.title = "新書名"; // 這行會報錯，因為 title 是唯讀的

```

    
## Required<Type>
這個型別將參數型別 **`Type`** 的所有屬性都設為必須，和 **`Partial<Type>`** 正好相反。

### 延續上面的圖書館範例
在某些情境下，我們希望確保所有這些屬性在建立時都能明確提供，來保持數據的完整性，就適合用 `Required<Type>`。

```tsx=
// 圖書介面，故意都設為 ?
interface LibraryBook {
  id?: number;
  title?: string;
  isCheckedOut?: boolean;
}

// 使用 Required 將 LibraryBook 的所有屬性變為必需
type CompleteLibraryBook = Required<LibraryBook>;

// 創建一個完整的圖書資訊，需要提供所有屬性
const book: CompleteLibraryBook = {
  id: 1,
  title: "深入淺出 TypeScript",
  isCheckedOut: false,
};

// 故意建立不完整的書本資訊
// const incompleteBook: CompleteLibraryBook = { id: 2 }; // 這行會報錯，因為 title 和 isCheckedOut 屬性有缺~

```
![截圖 2024-01-30 上午12.27.13](https://hackmd.io/_uploads/H1DefUH9a.png)

    
## Record<Keys, Type>
**`Record<Keys, Type>`** 用來將一種型別的屬性映射到另一種型別。

### 延續前面圖書館範例，記錄各圖書數量
在圖書館系統中，我們可能需要管理圖書館的不同區域和這些區域中的圖書數量。像是特定的圖書區域，例如 "文學"、"科學"、"歷史"。

```tsx
// 定義各區域的圖書數量資訊
interface BookCount {
  totalBooks: number;
  availableBooks: number;
}

// 定義圖書館區域的類型
type LibrarySection = "文學" | "科學" | "歷史";

// 使用 Record 建立一個物件型別
// key 為 LibrarySection
// Type 為 BookCount
const sectionBookCounts: Record<LibrarySection, BookCount> = {
  "文學": { totalBooks: 100, availableBooks: 80 },
  "科學": { totalBooks: 150, availableBooks: 120 },
  "歷史": { totalBooks: 90, availableBooks: 85 },
};

// 存取特定區域的圖書數量資訊
const literatureSection = sectionBookCounts["文學"];
//literatureSection 的 type 為 BookCount
//literatureSection 的 value 為 { totalBooks: 100, availableBooks: 80 }

```

## Pick<Type, Keys>
**`Pick<Type, Keys>`** 用途在要從一個型別 **`Type`** 中選取一組屬性 **`Keys`**（字串字面量、字串字面量+聯合型別）來建立一個新型別。

### 僅需顯示圖書的簡略資訊
假設有一個圖書介面 **`LibraryBook`**，屬性有 **`id`**、**`title`**、**`author`** 和 **`isCheckedOut`**（圖書是否被借出）。
    
在某些情況下，可能只需要從這個介面中選部分屬性，來顯示圖書的簡略資訊，而不是顯示所有細節時，就蠻適合使用`Pick<Type, Keys>`，來檢視以下範例：

```tsx
// 圖書介面
interface LibraryBook {
  id: number;
  title: string;
  author: string;
  isCheckedOut: boolean;
}

// 使用 Pick 從 LibraryBook 中選取 'title' 和 'isCheckedOut' 屬性來建立一個新型別
type BookPreview = Pick<LibraryBook, "title" | "isCheckedOut">;

// 建立一個圖書的簡略資訊
const bookPreview: BookPreview = {
  title: "深入淺出 TypeScript",
  isCheckedOut: true,
};

// bookPreview 只包含圖書的標題和借閱狀態，適合用於圖書借閱狀態的快速查看

```



## 小結
    
以上挑選相關工具型別，主要是很適合用在於 `interface`、`type` 的使用靈活性上能夠更具彈性。
    
    
## 問題
請挑選以下自己不熟悉的 Utility Type ，並嘗試撰寫程式碼來進行解讀，附上其它沒介紹到的：
    
1. Omit<Type, Keys>
1. Exclude<UnionType, ExcludedMembers>
1. Extract<Type, Union>
1. InstanceType<Type>
1. NonNullable<Type>
1. OmitThisParameter<Type>
1. Parameters<Type>
1. ReadonlyArray<Type>
1. ReturnType<Type>
1. ThisParameterType<Type>
1. ThisType<Type>
1. OrNull<Type>
1. OneOrMany<Type>
1. OneOrManyOrNull<Type>
1. ConstructorParameters<Type>
1. Awaited<Type>

## 回報區
    
|    Discord    |                          CodePen / 答案       | 挑選的工具型別                   |
|:-------------:|:----------------------------------------------------------------:|:----------------------------------------------------------------:|
|洧杰|[Codepen](https://codepen.io/hexschool/pen/poYgYqW?editors=1010)| Pick、ReturnType
|HsienLu|[Codepen](https://www.typescriptlang.org/play?#code/C4TwDgpgBAhgdgSwLYwDYF4BQAfARAQQBMB7Ac1x1wCETzKBhAYxmArwBEwE7Hi4BnYFABexYgC4AogA9GqAK6EIAHnjI0AGgAGAEgDeggE4I4pAL5dSWgHwBtALrpbBWrg3VX7pize5O3XHtMXgFiVAgAOlQyAApRYgBKTCA)|Exclude
|苡安|[Codepen](https://stackblitz.com/edit/typescript-bgaf14?file=index.ts)| Omit、Extract、Parameters
|hannahpun|[Blog](https://medium.com/hannah-lin/typescript-%E7%94%A8%E7%94%9F%E6%B4%BB%E4%BE%8B%E5%AD%90%E5%9C%96%E8%A7%A3-utility-type-2eeee27a58cd#f2be)| Parameters、ReturnType、Awaited、String Manipulation Types