上一篇介紹了 Generic 泛型, 其實這篇差不多意思 XDD 主要針對 Generic Function。
若有錯誤,歡迎留言指教,感恩的心。
以下例子想要取得帶入參數 array 第0個的值, 我們可以看到s
回傳值的型別會是 any
, 但我想要帶入不同的值對應的型別,該怎麼做呢。
function firstElement(arr: any[]) {
return arr[0];
}
const s = firstElement(["a", "b", "c"]);
const n = firstElement([1, 2, 3]);
console.log(s); //a
console.log(n); //1
我們可以使用泛型,我們在函式名後添加了 ,其中 Type 用來指代任意輸入的型別,讓型別推論自動推算出來。 可以看到變數s
會是string型別。而n
會是number型別。
function firstElement<Type>(arr: Type[]): Type {
return arr[0];
}
// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
console.log(s); //a
console.log(n); //1
除了使用<Type>
的方式, 可以傳入多組參數如<Input, Output>
,讓 TypeScript 自動 inferred 型別。
如下,n
被 inferred 為 string
, 而透過 parseInt 字串轉數字,最後 parsed
被 inferred 的型別是 number[]
。 Input
及 Output
命名可以自行定義。
function map<Input, Output>(
arr: Input[],
func: (arg: Input) => Output
): Output[] {
return arr.map(func);
}
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n, 10));
console.log(parsed); //[1,2,3]
以下函式有兩個傳入參數 a
及 b
, 我們預期他們傳入的型別都要有 length
屬性,我們這時候可以使用 extends
關鍵字來限制參數length
屬性,且指定length
是 number 型別。
我們可以看到只有 notOK 會報錯,因為傳入的參數 (10, 100)
不符 length
屬性。
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); //[1,2,3]
// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");
console.log(longerString); //alice
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);
//error: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
在官網有舉例在使用generic泛型約束的時候,可能會出錯的地方,可參考 這裏。
在使用 generic 中有些情況 TypeScript 無法自動inferred型別,我們可以自行指定:
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
return arr1.concat(arr2);
}
const arr = combine([1, 2, 3], ["hello"]);
//❌ error: Type 'string' is not assignable to type 'number'.
const arr = combine<string | number>([1, 2, 3], ["hello"]);
console.log(arr); //[1, 2, 3, "hello"]
// ⭕ 指定他為 string | number 聯合型別。
//⭕ 返回型別為 Type
function firstElement1<Type>(arr: Type[]) {
return arr[0];
}
//❌ 返回型別為 any
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]);
Always use as few type parameters as possible.
//⭕
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);
}
If a type parameter only appears in one location, strongly reconsider if you actually need it.
如果只使用到一種型別,我們應該用簡單的方式去寫即可。
//❌
function greet1<Str extends string>(s: Str) {
console.log("Hello, " + s);
}
greet1("world");
//⭕
function greet2(s: string) {
console.log("Hello, " + s);
}
greet2("world");
Day22 done. 感謝閱讀,明天見!
https://www.typescriptlang.org/docs/handbook/2/functions.html#generic-functions