爲下面描述的map函數添加一個更好的Typescript類型標註,提升使用者的類型安全性(若是不按下面的方式使用,就會報錯):html
map是一個用來作數組mapping的高階函數,先接收mapping function(將【輸入數組的項】映射爲【輸出數組的項】),而後接收輸入數組,返回輸出數組。
當mapping function沒有傳入時,mapping function默認爲一個不作任何轉化的函數(即x=>x
)。typescript
用代碼來表示,就是:數組
const map = (fn = x => x) => arr => { const result = []; for (const item of arr) { result.push(fn(item)); } return result; };
function map(): <V>(arr: V[]) => V[]; function map<V, R>(fn: (value: V) => R): (arr: V[]) => R[]; function map(fn = (x: any) => x) { return (arr: any[]) => { const result: any[] = []; for (const item of arr) { result.push(fn(item)); } return result; }; } // 測試 const emptyMap = map(); const result1 = emptyMap([1, 2, 3]); const result2 = emptyMap(["1", "2"]); const mapNumberToString = map((v: number) => "str"); const result3 = mapNumberToString([1, 2, 3]); // const result4 = mapNumberToString(["1", "2"]); // 報錯,類型檢查有效 // const mapNumberToString2 = map((v: number) => "str", [1, 2]); // 報錯,類型檢查有效
事實上類型推導也可以作到(雖然可維護性降低不少),就當作是對Typescript類型推導的一個練習吧!app
真實項目中遇到這種狀況,應該選擇可維護性更高的方式。
type FnBasic = (value: any) => any; type InferV<Fn> = Fn extends ((value: infer V) => any) ? V : never; type InferR<Fn> = Fn extends ((value: any) => infer R) ? R : never; const map = <Args extends [FnBasic?]>(...args: Args) => { // 經過tuple types來拿到可選參數的實際類型 // https://stackoverflow.com/a/51489032 type FnType = Args[0]; const fn: FnBasic = args[0] || (x => x); type ReturnType = FnType extends (undefined) ? <V>(arr: V[]) => V[] // 返回一個帶泛型的函數,從而V可以在被調用時肯定 : (arr: InferV<FnType>[]) => InferR<FnType>[]; // V已經可以推導出來 const ret: ReturnType = ((arr: any[]) => { const result = []; for (const item of arr) { result.push(fn(item)); } return result; }) as any; return ret; }; // 測試 const emptyMap = map(); const result1 = emptyMap([1, 2, 3]); const result2 = emptyMap(["1", "2"]); const mapNumberToString = map((v: number) => "str"); const result3 = mapNumberToString([1, 2, 3]); // const result4 = mapNumberToString(["1", "2"]); // 報錯,類型檢查有效 // const mapNumberToString2 = map((v: number) => "str", [1, 2]); // 報錯,類型檢查有效
其中主要的知識點是:函數