iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
JavaScript

TypeScript Type Challenges 冒險篇章:30 天闖關之旅,type 簡單了?你確定?系列 第 15

第15關:Omit!TypeScript Expelliarmus:去去,屬性走

  • 分享至 

  • xImage
  •  

第15關:Omit

關卡簡介

Implement the built-in Omit<T, K> generic without using it.

Constructs a type by picking all properties from T and then removing K

實現內建的 Omit<T, K> 泛型,不使用內建版本。

透過選取 T 中的所有屬性,然後移除 K,來構造一個型別。

任務說明:

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = MyOmit<Todo, 'description' | 'title'>

const todo: TodoPreview = {
  completed: false,
}

type a = MyReturnType<typeof fn> // should be "1 | 2"

接下來,你的任務是讓下面的type cases測試通過:

type cases = [
  Expect<Equal<Expected1, MyOmit<Todo, 'description'>>>,
  Expect<Equal<Expected2, MyOmit<Todo, 'description' | 'completed'>>>,
  Expect<Equal<Expected3, MyOmit<Todo1, 'description' | 'completed'>>>,
]

interface Todo {
  title: string
  description: string
  completed: boolean
}

interface Todo1 {
  readonly title: string
  description: string
  completed: boolean
}

interface Expected1 {
  title: string
  completed: boolean
}

interface Expected2 {
  title: string
}

interface Expected3 {
  readonly title: string
}

冒險指南:

從以下幾個方向來思考:

  • 推導返回型別 (Inferring the Return Type): 我們的目標是從類型 T 中挑出屬性,並排除 K。可以使用條件型別搭配 keyof 來推導出結果型別。

  • 條件型別與映射型別 (Conditional and Mapped Types): 你會需要將條件型別與映射型別結合,來過濾屬性並構造新的型別。

  • 泛型 (Generics): 設定 T 為泛型,並且將 K 作為需要被移除的屬性集。在構建映射型別時,確保靈活排除這些屬性。

通關方式:

解法1:

type MyOmit<T, K extends keyof T> = {
    [P in keyof T as P extends K? never:P]:T[P]
  }

細節分析:

  • 泛型參數 (Generic Parameters):
    • K extends keyof TK 是要移除的屬性,並且必須是 T 的屬性鍵之一。這樣的限制可以確保只會移除有效的屬性,避免處理不存在的屬性。
  • 條件型別與推斷 (Conditional Types and Inference):
    • 使用條件型別 P extends K ? never : P 來判斷 P是否屬於 K。如果屬於,就會返回 never,從而排除該屬性;如果不屬於,則保留屬性 P。這樣可以靈活地移除指定的屬性,保留其他屬性。
  • 映射型別 (Mapped Types):
    • [P in keyof T] 是 TypeScript 中的映射型別語法,用來迭代 T 的所有屬性。結合條件型別,它能實現根據 K 排除指定屬性的功能。
    • [P in keyof T as P extends K ? never : P] 中的 as 語法提供了一個條件過濾機制,用來判斷哪些屬性應該被保留。當條件成立時,它會讓屬性名被過濾掉 (never),否則屬性名會保留。這是 TypeScript 提供的一種靈活的方式來映射型別。

解法2:

type MyOmit<T, K extends keyof T> = {

 [P in keyof T as Exclude<P, K>]: T[P]
  }

細節分析:

  • 條件型別與工具型別 (Conditional Types and Utility Types):

  • 使用工具型別 Exclude<P, K>,該工具型別會將 PK 中排除。與 P extends K ? never : P 的邏輯相似,但 Exclude 是內建的工具型別,更加簡潔明瞭。

這樣,我們就能順利通過測試啦 🎉 😭 🎉

關鍵字補給:

Mapped Types (Key Remapping via as) - 未來補充 😭

總結:

本次介紹了 Omit 的實作,下一關會挑戰 Readonly,期待再相見!


上一篇
第14關:Get Return Type!TypeScript 預言家:看見返回型別
下一篇
第16關:Readonly 2!TypeScript 可遠觀不可褻玩焉: Readonly 保護罩 2
系列文
TypeScript Type Challenges 冒險篇章:30 天闖關之旅,type 簡單了?你確定?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言