为下面描述的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]); // 报错,类型检查有效
其中主要的知识点是:函数