您将这种 TypeScript 无法做到的推理称为什么?

What would you call this type of inference that TypeScript can not do?

目前使用 TypeScript,如果给 map 一个函数,则无法推断数组的类型。

> let rfn1 = (a, fn:((x:number)=>number) ) => a.map(fn);

> .type rfn1

let rfn1: (a: any, fn: (x: number) => number) => any

您可以看到 aany 类型,即使它必须是 number[] 类型才能为类型 ((x:number)=>number) 的函数提供有效参数。

同样,你可以看到这个问题可以用显式类型来解决,

> let rfn2 = (a: number[], fn:((x:number)=>number) ) => a.map(fn);

> .type rfn2
let rfn9: (a: number[], fn: (x: number) => number) => number[]

您认为此处目前缺少的需要显式输入的推理类型是什么?

我能理解您的思路...但这取决于许多无法证明的假设。所以我会调用 a 类型的扩展:

Widened type due to unprovable assumptions

如果您从最内部开始工作,您有一个 兼容 的函数,其中包含 array.map:

的回调函数
(value: number, index: number, array: number[]) => {}

我们必须假设我们知道的关于 ((x: number) => number) 的函数类型只能用于 array.map - 这是第一个无法证明的假设。

将我们的视野更进一步,我们有a.map(...)。这个 可能 array.map,但它也可能是 geoAwesome.map 或我们创建了 map 方法的任何其他字面意思。所以假设 a.maparray.map 是我们第二个无法证明的假设。

即使结合两个假设,我们仍然无法证明a 一定是一个数组

class NotArray {
  map(fn: (num: number) => number) {
    return fn(3);
  }
}

let rfn1 = (a, fn: ((x: number) => number)) => a.map(fn);

let res1 = rfn1([1, 2, 3], (x) => x);
console.log(res1);

let res2 = rfn1(new NotArray(), (x) => x);
console.log(res2);

看看这个人为设计的示例,您可以看到 a 实际上可以是任何类型(只要它具有兼容的 map 方法即可。因此,any.

只有当我们注释 a 参数时,编译器才能证明 a 不是那些其他类型 - 现在我们的 res2 示例将产生错误。

let rfn1 = (a: number[], fn: ((x: number) => number)) => a.map(fn);