TypeScript 的 generic 區別是什麼?

編寫一個函數,其中輸入的類型與輸出的類型相關,或者兩個輸入的類型以某種方式相關。 讓咱們考慮一個返回數組第一個元素的函數:數組

function firstElement(arr: any[]) {
return arr[0];
}
這個函數完成了它的工做,但不幸的是返回類型爲 any。 若是函數返回數組元素的類型會更好。ide

在 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);ui

TypeScript 的類型推斷 - Type inference
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
return arr.map(func);
}
注意,上面代碼的 Inout,Output 能夠被 T, V 替代,可是可讀性不如前者。code

Type constrains - 類型約束
咱們已經編寫了一些能夠處理任何類型值的通用函數。 有時咱們想關聯兩個值,但只能對某個值的子集進行操做。 在這種狀況下,咱們可使用約束來限制類型參數能夠接受的類型種類。ip

讓咱們編寫一個函數,返回兩個值中較長的一個。 爲此,咱們須要一個長度屬性,它是一個數字。 咱們經過編寫 extends 子句將類型參數限制爲該類型:ci

function longest<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {get

return a;

} else {string

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 的屬性。it

同 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 Typewww.diuxie.com 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);

相關文章
相關標籤/搜索