Implement the built-in
ReturnType<T>
generic without using it.
實現內建的 ReturnType<T>
泛型,而不使用內建的版本
const fn = (v: boolean) => {
if (v)
return 1
else
return 2
}
type a = MyReturnType<typeof fn> // should be "1 | 2"
接下來,你的任務是讓下面的type cases測試通過:
type cases = [
Expect<Equal<string, MyReturnType<() => string>>>,
Expect<Equal<123, MyReturnType<() => 123>>>,
Expect<Equal<ComplexObject, MyReturnType<() => ComplexObject>>>,
Expect<Equal<Promise<boolean>, MyReturnType<() => Promise<boolean>>>>,
Expect<Equal<() => 'foo', MyReturnType<() => () => 'foo'>>>,
Expect<Equal<1 | 2, MyReturnType<typeof fn>>>,
Expect<Equal<1 | 2, MyReturnType<typeof fn1>>>,
]
從以下幾個方向來思考:
解法:
type MyReturnType<T extends (...arg: any[]) => any> = T extends (...arg: any[]) => infer A ? A : never
細節分析:
泛型參數 (Generic Parameters):
T extends (...args: any) => any
:這裡 T
被明確限制為一個函式型別,它可以接受任何數量的參數,並且返回任意型別。這個限制確保我們的泛型 T
必須是函式型別,避免對非函式型別進行操作。條件型別與推斷 (Conditional Types and Inference):
T extends (...arg: any[]) => infer A
,透過 infer
來推斷 T
函式的返回型別 A。如果 T 是函式型別,則會推斷並返回其返回值的型別;如果不是,則返回 never
。這裡 infer
是關鍵,它負責提取返回值型別。停止條件 (Stopping Conditions):
T
不是函式型別時,返回 never
,防止處理非預期的型別。這樣的設計也處理了無參數函式的情況,讓 infer A
自動推斷空參數函式的返回值。這樣,我們就能順利通過測試啦 🎉 😭 🎉
這是初版解法,想了想不夠好,為什麼呢?
缺乏明確的型別限制 (Lack of Clear Type Restriction)
type MyReturnType0<T> = T extends (...arg: any[]) => infer A ? A : never
在這段代碼中,雖然使用 MyParameters0<T>
也不會報錯,但這種寫法其實不夠嚴謹,原因在於對 T
的約束過於寬泛。在 MyParameters0<T>
中,T
可以是任何型別,沒有任何限制或條件。也就是說,T 不一定非得是函式型別,這會導致該泛型對不應用於函式的型別也能通過編譯,但這不是我們的想要的行為。
(使用 typeof
看一下分別會返回什麼型別吧)
未來補充 😭
本次介紹了 Get Return Type
的實作,下一關會挑戰 Omit
,期待再相見!