TypeScript自定义map函数传入参数数量不符的函数时未触发类型报错的问题
TypeScript自定义map函数传入参数数量不符的函数时未触发类型报错的问题
嘿,我懂你现在的困惑——你写的这个自定义map函数明明要求传入的fn必须接收两个参数(数组元素和索引),但实际用的时候如果传一个只接受单个参数的函数,TypeScript居然没抛出类型错误,对吧?
先把你的代码贴出来方便大家参考:
function map(arr: number[], fn: (n: number, i: number) => number): number[] { let returnedArray: number[] = []; for (let index = 0; index < arr.length; index++) { returnedArray.push(fn(arr[index], index)); } return returnedArray; }
这其实是TypeScript的函数参数兼容性规则在起作用:TypeScript允许传入参数数量更少的函数来适配参数数量更多的函数类型。原因很简单——当我们调用fn(arr[index], index)时,就算fn只用到第一个参数,第二个参数会被直接忽略,代码依然能正常运行,TypeScript认为这种场景是安全的,所以默认不会报错。
举个实际调用的例子,你这么写完全不会触发类型错误:
// 这个回调只接受一个参数,但TypeScript无报错 map([1,2,3], (n) => n * 2);
如果你希望强制要求fn必须显式接收两个参数,有两种常用的解决办法:
方法一:用元组类型限制参数数量
定义一个严格要求接收两个参数的函数类型,再用它来约束fn:
// 明确要求函数必须接收恰好两个number类型参数 type TwoArgCallback = (...args: [number, number]) => number; function map(arr: number[], fn: TwoArgCallback): number[] { let returnedArray: number[] = []; for (let index = 0; index < arr.length; index++) { returnedArray.push(fn(arr[index], index)); } return returnedArray; }
这样再传入只接受单个参数的函数,TypeScript就会立刻抛出类型错误,达到你要的强约束效果。
方法二:使用函数重载
通过重载签名来限制外部调用时的参数要求:
// 对外暴露的重载签名,强制回调必须接收两个参数 function map(arr: number[], fn: (n: number, i: number) => number): number[]; // 内部实现签名,可以兼容可选参数,但外部调用会被重载签名约束 function map(arr: number[], fn: (n: number, i?: number) => number): number[] { let returnedArray: number[] = []; for (let index = 0; index < arr.length; index++) { returnedArray.push(fn(arr[index], index)); } return returnedArray; }
这种方式下,外部调用map时必须传入符合两个参数要求的回调,否则会触发类型提示错误。
其实TypeScript默认的参数兼容性设计是为了灵活性——很多场景下我们确实不需要用到索引,只处理元素就够了,默认允许这种写法能减少冗余代码。但如果你有强类型约束的需求,上面两种方法都能完美解决你的问题。
备注:内容来源于stack exchange,提问作者Alex CHEN
相关产品推荐
相关产品推荐

