TypeScript 的 generic 函数
官方鏈接
編寫一個函數,其中輸入的類型與輸出的類型相關,或者兩個輸入的類型以某種方式相關。 讓我們考慮一個返回數組第一個元素的函數:
function firstElement(arr: any[]) {return arr[0]; }這個函數完成了它的工作,但不幸的是返回類型為 any。 如果函數返回數組元素的類型會更好。
在 TypeScript 中,當我們想要描述兩個值之間的對應關系時,會使用泛型。 我們通過在函數簽名中聲明一個類型參數來做到這一點:
function firstElement<T>(arr: T[]): T {return arr[0]; }const arr: string[] = ['1', '2', '3'];const result = firstElement(arr);console.log(result);const result1:number = firstElement(arr);TypeScript 的類型推斷 - Type inference
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {return arr.map(func); }注意,上面代碼的 Inout,Output 可以被 T, V 替代,但是可讀性不如前者。
Type constrains - 類型約束
我們已經編寫了一些可以處理任何類型值的通用函數。 有時我們想關聯兩個值,但只能對某個值的子集進行操作。 在這種情況下,我們可以使用約束來限制類型參數可以接受的類型種類。
讓我們編寫一個函數,返回兩個值中較長的一個。 為此,我們需要一個長度屬性,它是一個數字。 我們通過編寫 extends 子句將類型參數限制為該類型:
function longest<Type extends { length: number }>(a: Type, b: Type) {if (a.length >= b.length) {return a;} else {return b;} }// longerArray is of type 'number[]' const longerArray = longest([1, 2], [1, 2, 3]); console.log(longerArray);// longerString is of type 'string' const longerString = longest("alice", "bob"); console.log(longerString);// Error! Numbers don't have a 'length' property const notOK = longest(10, 100);最后一個函數調用會出現編譯錯誤,因為 TypeScript 基本類型 number 并不存在名稱為 length 的屬性。
同 Java 相比,TypeScript 的類型約束的強大之處在于,extends 后面緊跟的不需要是 TypeScript 的 built-in type,比如本例里的:
{ length: number }意思是,只要該函數傳入的類型,至少包含類型為 number 的 length 屬性即可。
Specifying Type Arguments
TypeScript 通常可以在泛型調用中推斷出預期的類型參數,但并非總是如此。 例如,假設您編寫了一個函數來組合兩個數組:
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {return arr1.concat(arr2); }編譯錯誤:
解決辦法:使用尖括號語法,顯式傳入類型參數:這里 T = string | number,意思是接收 string 或者 number 類型均可。
編寫 generic 函數的最佳實踐
編寫泛型函數很有趣,而且很容易被類型參數沖昏頭腦。 有太多類型參數或在不需要它們的地方使用約束會使推理不那么成功,使函數的調用者感到沮喪。
最佳實踐1 - Push Type Parameters Down
function firstElement1<Type>(arr: Type[]) {return arr[0]; }function firstElement2<Type extends any[]>(arr: Type) {return arr[0]; }// a: number (good) const a = firstElement1([1, 2, 3]); // b: any (bad) const b = firstElement2([1, 2, 3]);乍一看,兩種方法似乎相同,但 firstElement1 是編寫此函數的更好方法。 它的推斷返回類型是 Type,但 firstElement2 的推斷返回類型是 any,因為 TypeScript 必須使用約束類型解析 arr[0] 表達式,而不是在調用期間“等待”解析元素。
最佳實踐 2- Use Fewer Type Parameters
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {return arr.filter(func); }function filter2<Type, Func extends (arg: Type) => boolean>(arr: Type[],func: Func ): Type[] {return arr.filter(func); }我們創建了一個不關聯兩個值的類型參數 Func。 這總是一個危險信號,因為這意味著想要指定類型參數的調用者必須無緣無故地手動指定一個額外的類型參數。 Func 不會做任何事情,只會讓函數更難閱讀和推理!
最佳實踐3 - Type Parameters Should Appear Twice
function greet<Str extends string>(s: Str) {console.log("Hello, " + s); }greet("world");這個例子里, Str 只出現了一次,因此根本毫無必要。
可以簡寫成:
function greet(s: string) {console.log("Hello, " + s); }請記住,類型參數用于關聯多個值的類型。 如果一個類型參數在函數簽名中只使用一次,它就沒有任何關系。
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的TypeScript 的 generic 函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详细解读DialogFragment
- 下一篇: TypeScript void 和 un