iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
JavaScript

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

第13關:Parameters!TypeScript Expecto Patronum : "疾疾,參數現身"

  • 分享至 

  • xImage
  •  

第13關:Parameters

關卡簡介

Implement the built-in Parameters generic without using it.

不使用內建的 Parameters 泛型,實作其功能
(我們希望使用 MyParameters 泛型 (generic) 來提取任意函式 (function) 的參數型別 (parameter types),讓它返回對應的參數型別列表 (list of parameter types)。)

任務說明:

const foo = (arg1: string, arg2: number): void => {}

type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]

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

type cases = [
  Expect<Equal<MyParameters<typeof foo>, [string, number]>>,
  Expect<Equal<MyParameters<typeof bar>, [boolean, { a: 'A' }]>>,
  Expect<Equal<MyParameters<typeof baz>, []>>,
]

冒險指南:

從以下幾個方向來思考:

  1. 提取參數型別 (Extracting Parameter Types): 考慮如何從函式型別中提取出它的參數,這是一個關鍵步驟,可能需要透過條件型別 (conditional types) 來進行判斷。
  2. 使用推導來拆解 (Using Inference for Decomposition): 可以利用 TypeScript 的推導能力 (infer) 來拆解函式型別並提取其參數列表。
  3. 應對空參數函式 (Handling Functions Without Parameters): 如果函式沒有任何參數,應返回空陣列 (empty array) [],這是處理特殊情況的步驟。

通關方式:

解法:

    type MyParameters<T extends (...args:any) => unknown> = T extends (...arg: infer A) => unknown ? A : never

細節分析:

  • 泛型參數 (Generic Parameters):

    • T extends (...args: any) => unknown:這裡的 T 被限制為一個函式型別,它接受任何參數 (any) 並返回一個未知值 (unknown)。
    • 這種限制確保我們的泛型 T 是一個函式,因為 Parameters 泛型專門用來提取函式的參數型別。
  • 條件型別與推斷 (Conditional Types and Inference):

    • 使用 T extends (...arg: infer A) => unknown,我們利用 infer 關鍵字來推斷出函式的參數列表 A。
    • 如果 T 符合這個條件 (T 是函式),則會推斷出參數列表 A 並返回它;如果不符合條件,則返回 never。
      這裡的推斷 (infer) 是關鍵,它負責提取出函式的參數型別,類似於 Parameters 的功能。
  • 遞迴與停止條件 (Recursion and Stopping Conditions):

    • 雖然這個實作並不需要遞迴,但條件型別中有隱含的「終止條件」。當 T 不是函式型別時,返回 never,這相當於處理異常或不匹配的情況,確保函式參數列表提取的正確性。
    • 對於沒有參數的函式,infer A 會自動推斷為 [],這樣就處理了函式沒有參數的情況。

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

其他補充:

這是初版解法,想了想不夠好,為什麼呢?
缺乏明確的型別限制 (Lack of Clear Type Restriction)

    type MyParameters0<T> = T extends (...arg: infer A) => unknown ? A : never

在這段代碼中,雖然使用 MyParameters0<T> 也不會報錯,但這種寫法其實不夠嚴謹,原因在於對 T 的約束過於寬泛。在 MyParameters0<T>中,T 可以是任何型別,沒有任何限制或條件。也就是說,T 不一定非得是函式型別,這會導致該泛型對不應用於函式的型別也能通過編譯,但這不是我們的想要的行為。

關鍵字補給:

未來補充 😭

總結:

本次介紹了 Parameters 的實作,下一關會挑戰 Get Return Type,期待再相見!


上一篇
第12關:Push + Unshift!TypeScript 貪食蛇:如何靈活控制陣列頭尾
系列文
TypeScript Type Challenges 冒險篇章:30 天闖關之旅,type 簡單了?你確定?13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言