PAYATHON 2026

为什么 Array.map(f) 会推断出 number[][]?

数据小陈

结论

map 不会因为回调返回数组就额外“包裹”结果。它总会返回一个新数组,里面包含每次回调的返回值。题目中的 number[][] 表示 TypeScript 检查 [1, 2, 3].map(f) 时,将回调的返回类型推断为 number[],所以 map 的返回类型是 number[][]。运行时,回调 f 接收的是单个数字,最终结果仍是一维数字数组。

map 的类型如何形成

map 的类型关系可以简化为:输入元素类型是 T,回调返回类型是 U,整个调用的返回类型就是 U[]。因此,要看传给 map 的回调被推断为返回什么类型:

  • 回调返回 number 时,map 返回 number[]。
  • 回调返回 number[] 时,map 返回 number[][]。

题目中的 f 有两个重载:传入单个数字时返回数字,传入数字数组时返回数字数组。直接把这个泛型重载函数作为回调时,TypeScript 会检查它是否兼容 map 所需的回调类型,并进行类型推断。这里推断出的回调返回类型与显式调用 f(v) 时不同,因此多出了一层数组类型。

具体选择哪个重载以及泛型如何推断,可能受 TypeScript 版本和完整类型上下文影响。题目没有提供版本信息,因此不能把这个现象归结为某条固定的内部规则。可以确定的是,number[][] 是静态推断结果,不代表运行时的 map 会把每个数字转换成数组。

推荐写法:显式包装调用

用箭头函数明确地把当前数字传给 f:

const result = [1, 2, 3].map((v) => f(v))
// result: number[]

这里 f(v) 接收单个数字并返回数字,map 汇总这些返回值后得到 number[]。如果只是对数组中的每个数字执行相同运算,也可以直接写成:

const result = [1, 2, 3].map((v) => 2 * v)
// result: number[]

注意事项

类型推断是编译器对表达式的静态判断,不会改变 JavaScript 的运行时行为。把带有多个泛型重载的函数直接作为回调传入时,如果得到的类型不符合预期,可以用箭头函数显式调用来消除歧义。要确认特定项目中的推断细节,可以结合该项目使用的 TypeScript 版本检查最小复现代码。

备注:内容仅供参考。