TypeScript 是一種由微軟開發的開源編程語言,它是 JavaScript 的一個超集,添加了可選的靜態類型和基于類的面向對象編程。隨著 TypeScript 的不斷發展,新的語法和特性不斷被引入,以幫助開發者更高效地編寫類型安全的代碼。其中,infer extends
是 TypeScript 4.7 引入的一個新特性,它允許我們在條件類型中更靈活地推斷類型,并且可以對推斷出的類型進行進一步的約束。
本文將詳細介紹 infer extends
的使用方法,并通過多個示例來展示其在實際開發中的應用場景。
infer extends
?在 TypeScript 中,infer
關鍵字通常用于在條件類型中推斷類型。例如,我們可以使用 infer
來提取函數類型的返回類型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
在這個例子中,infer R
用于推斷函數類型的返回類型 R
。
然而,在某些情況下,我們可能希望對推斷出的類型進行進一步的約束。例如,我們可能希望推斷出的類型必須是某個特定類型的子類型。這就是 infer extends
的用武之地。
infer extends
允許我們在推斷類型的同時,對推斷出的類型進行約束。它的語法如下:
T extends infer U extends Constraint ? U : never;
在這個語法中,U
是推斷出的類型,Constraint
是對 U
的約束條件。如果 U
滿足 Constraint
,則返回 U
,否則返回 never
。
infer extends
的基本用法讓我們通過一個簡單的例子來理解 infer extends
的基本用法。
假設我們有一個類型 MaybeNumber
,它可以是 number
類型,也可以是 null
或 undefined
。我們希望定義一個類型 NumberOrNever
,如果 MaybeNumber
是 number
類型,則返回 number
,否則返回 never
。
type NumberOrNever<T> = T extends infer U extends number ? U : never;
在這個例子中,U
是推斷出的類型,extends number
是對 U
的約束條件。如果 U
是 number
類型,則返回 U
,否則返回 never
。
讓我們測試一下這個類型:
type A = NumberOrNever<number>; // number
type B = NumberOrNever<string>; // never
type C = NumberOrNever<null>; // never
type D = NumberOrNever<undefined>; // never
正如我們所期望的那樣,NumberOrNever<number>
返回 number
,而其他類型返回 never
。
infer extends
的高級用法infer extends
不僅可以用于簡單的類型約束,還可以用于更復雜的場景。讓我們通過幾個例子來展示其高級用法。
假設我們有一個數組類型 Array<T>
,我們希望提取數組元素的類型 T
,并且要求 T
必須是 number
或 string
類型。
type ArrayElement<T> = T extends Array<infer U extends number | string> ? U : never;
在這個例子中,U
是推斷出的數組元素的類型,extends number | string
是對 U
的約束條件。如果 U
是 number
或 string
類型,則返回 U
,否則返回 never
。
讓我們測試一下這個類型:
type A = ArrayElement<number[]>; // number
type B = ArrayElement<string[]>; // string
type C = ArrayElement<boolean[]>; // never
type D = ArrayElement<(number | string)[]>; // number | string
假設我們有一個函數類型 FunctionType
,我們希望提取函數的第一個參數的類型,并且要求該參數必須是 string
類型。
type FirstParameter<T> = T extends (arg: infer U extends string, ...args: any[]) => any ? U : never;
在這個例子中,U
是推斷出的函數第一個參數的類型,extends string
是對 U
的約束條件。如果 U
是 string
類型,則返回 U
,否則返回 never
。
讓我們測試一下這個類型:
type A = FirstParameter<(arg: string) => void>; // string
type B = FirstParameter<(arg: number) => void>; // never
type C = FirstParameter<(arg: string, arg2: number) => void>; // string
假設我們有一個對象類型 ObjectType
,我們希望提取對象中某個屬性的類型,并且要求該屬性必須是 number
類型。
type PropertyType<T, K extends keyof T> = T[K] extends infer U extends number ? U : never;
在這個例子中,U
是推斷出的對象屬性的類型,extends number
是對 U
的約束條件。如果 U
是 number
類型,則返回 U
,否則返回 never
。
讓我們測試一下這個類型:
type A = PropertyType<{ a: number, b: string }, 'a'>; // number
type B = PropertyType<{ a: number, b: string }, 'b'>; // never
type C = PropertyType<{ a: number, b: number }, 'b'>; // number
infer extends
的實際應用場景infer extends
在實際開發中有許多應用場景,特別是在需要精確控制類型推斷的情況下。以下是一些常見的應用場景:
在處理 API 響應時,我們通常希望確保響應數據的類型符合預期。例如,我們可能希望確保某個字段是 number
類型。使用 infer extends
,我們可以在類型層面進行這種約束。
type ApiResponse<T> = {
data: T;
status: number;
};
type SafeNumberResponse<T> = ApiResponse<T> extends { data: infer U extends number } ? U : never;
type ResponseA = SafeNumberResponse<{ data: number }>; // number
type ResponseB = SafeNumberResponse<{ data: string }>; // never
在編寫高階函數時,我們可能希望確保傳入的函數參數符合特定的類型約束。使用 infer extends
,我們可以在類型層面進行這種約束。
type FunctionWithStringArg<T> = T extends (arg: infer U extends string) => any ? U : never;
type FuncA = FunctionWithStringArg<(arg: string) => void>; // string
type FuncB = FunctionWithStringArg<(arg: number) => void>; // never
在處理配置對象時,我們可能希望確保某些配置項的類型符合預期。使用 infer extends
,我們可以在類型層面進行這種約束。
type Config<T> = {
option: T;
};
type SafeNumberConfig<T> = Config<T> extends { option: infer U extends number } ? U : never;
type ConfigA = SafeNumberConfig<{ option: number }>; // number
type ConfigB = SafeNumberConfig<{ option: string }>; // never
infer extends
是 TypeScript 4.7 引入的一個強大的新特性,它允許我們在條件類型中更靈活地推斷類型,并且可以對推斷出的類型進行進一步的約束。通過 infer extends
,我們可以在類型層面實現更精確的類型控制,從而提高代碼的類型安全性和可維護性。
在實際開發中,infer extends
可以應用于多種場景,如 API 響應處理、函數參數處理、配置對象處理等。通過合理地使用 infer extends
,我們可以編寫出更加健壯和可靠的 TypeScript 代碼。
希望本文能夠幫助你理解并掌握 infer extends
的使用方法,并在實際項目中靈活運用這一特性。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。