【问题标题】:Why does TypeScript not infer function parameters types when those parameters are passed to a typed function?当这些参数传递给类型化函数时,为什么 TypeScript 不推断函数参数类型?
【发布时间】:2020-02-11 00:25:30
【问题描述】:

在以下示例中:

function functionA(x: string, y: number, z: SpecialType): void { }
const functionWrapper: (x, y, z) => functionA(x, y, z);

functionWrapper 的参数类型为any。有没有办法 鼓励 tsc 从他们的使用中推断出他们的类型? TypeScript 类型系统的哪些限制阻止了这个问题的解决?

【问题讨论】:

  • 我认为函数签名通常不会被推断出来。如果您要定义一个函数,则由您指定其签名。

标签: typescript types


【解决方案1】:

TypeScript 类型分析以自上而下的方式工作。这意味着它等于数据也是自上而下传递的程序数据流。 TypeScript 正在分析控制流,但它使用的是从顶部而不是底部给出的信息。

考虑这样的函数示例:

function functionMaker(x: string, y: string) { 
    return () => x + y; 
}

上面的函数返回另一个函数。在返回的匿名函数的定义中没有显式键入,但 TS 能够分析 functionMaker 总是返回 () => string 类型的函数。

换一种方式是不可能的,因为 TS 无法准确预测您将如何处理这些参数。考虑如下:

function functionA(x: string, y: number, z: SpecialType): void { }
function functionB(x: number): void { }
const functionWrapper: (x, y, z) => { 
  functionA(x, y, z);  // x should be string
  functionB(x); // x should be number
}

现在 TS 有两个函数都使用一个参数,但是它们都有不同的类型要求。任何解决这个难题的方法都是错误的,因为一个或另一个函数都会失败。

总之 - 类型分析是自上而下进行的。但是我们可以通过创建将包装另一个的通用函数来解决您的问题。

function functionA(x: string, y: number, z: SpecialType): void { }

const wrap = <X, Y, Z, R>(f: (x: X, y: Y, z: Z) => R) => (x: X, y: Y, z: Z): R => f(x,y,z);
const functionWrapper = wrap(functionA);

我们的wrap 被明确定义为一个包装器,这意味着它的目的是从给定函数推断类型并创建另一个具有相同参数和相同返回的函数。

【讨论】:

    【解决方案2】:

    一个原因:根据您的提议,如果 Typescript 可以自动缩小签名,它将隐式传播到所有调用站点并导致它们失败。

    function yourFunction(x) {
      doSomethingThatTakesANumber(x);
    }
    // elsewhere
    yourFunction(1);
    // still elsewhere
    yourFunction(-1);
    

    一旦将yourFunction 更改为doSomethingThatTakesABoolean,Typescript 会推断x 必须是布尔值,然后两个不相关的调用将开始失败。这将特别难以调试。

    对于编写一个与它所包装的函数具有相同签名的包装器函数的情况,您可以使用typeof functionA 来包装该函数,而无需重复自己。 Typescript 可以从函数的类型推断参数的类型,但不能从函数体中表达的代码推断出来。

    const functionWrapper2: typeof functionA = (x, y, z) => functionA(x, y, z);
    

    typescript playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-28
      • 2016-11-01
      • 2020-07-14
      • 2013-11-03
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多