【问题标题】:TypeScript type inferenceTypeScript 类型推断
【发布时间】:2018-07-03 04:21:55
【问题描述】:

在下面的代码中,我尝试创建一个类型安全的函数来访问给定输入的data 属性。我的目标是避免在任何地方重复访问data,为此我希望将样板代码保持在最低限度(例如,我希望 TypeScript 推断出尽可能多的类型)。

interface User {
    name: string
}

interface HttpResponse<T> {
    data: T
    status: number
}

type HttpPromise<T> = Promise<HttpResponse<T>>

function fetch<T>(url: string): HttpPromise<T> {
    return
}

function getData<T>(response: HttpResponse<T>): T {
    return response.data
}

// Doesn't work: 'Promise<{}>' is not assignable to type 'Promise<User>'.
function fetchUser(): Promise<User> {
    return fetch('https://...').then(getData)
}

我知道如何通过明确声明更多类型来使其工作,但我不知道为什么这还不起作用。特别是:

  1. {} 类型从何而来(在Promise&lt;{}&gt; 中)?
  2. 为什么 TypeScript 不能根据返回类型正确推断表达式的类型?

Link to TypeScript's playground with the code.

【问题讨论】:

    标签: typescript type-inference


    【解决方案1】:

    让我们从解决方案开始:

    function fetchUser(): Promise<User> {
        return fetch<User>('https://...').then(getData)
    }
    

    为了使类型推断起作用,我们需要为 TypeScript 提供一个起点,在本例中是我们用来启动执行的函数。如果我们让 fetch 方法的泛型 T 参数具有默认值(即 {}),那么 TypeScript 将使用该类型来确定所有连接的函数调用,基本上使 thengetData 继承该默认类型。最后,当 TypeScript 必须验证最后一个函数签名 (getData) 和外部 fetchUser 签名之间的类型正确性时,它会发现冲突,因为 getData 假定适用于 {} 类型,并且 fetchUser 明确声明它适用于 User 类型。

    您可以比较当您完全省略 fetchUser 函数返回的类型时,TypeScript 将如何计算返回的类型:

    function fetchUser() {
        return fetch<User>('https://...').then(getData)
    }
    

    如果您将鼠标悬停在 fetchUser 函数上,您将看到 TypeScript 从内部 fetch 函数签名推断用户类型,并且它仍然是 Promise

    【讨论】:

      【解决方案2】:

      对于您的第一个问题,TypeScript 抱怨类型为 Promise&lt;{}&gt; 的原因是,如果您没有为返回承诺的泛型函数指定类型,则默认为 Promise&lt;{}&gt;

      考虑到这一点,通过调用fetch('http://...'),而不提供类型参数,TypeScript 将推断它是Promise&lt;HttpResponse&lt;{}&gt;&gt;

      我假设您可以通过在 fetchUser 中调用 fetch 时指定 User 类型使其工作,如下所示:

      return fetch<User>('https://...').then(getData);
      

      如果您直接将呼叫返回到fetch,您正在寻找的推理将起作用。比如:

      async function getValueAsync<T>(): Promise<T> {
          return null;
      }
      
      function testGetValueAsync(): Promise<User> {
          return getValueAsync();
      }
      

      但是,由于您正在链接该调用,因此 fetch 调用中没有任何内容可以告诉 TypeScript 它返回的是什么类型。

      因此,您需要做的最小更改是在调用fetch 时指定User 类型

      return fetch<User>('https://...').then(getData);
      

      【讨论】:

        猜你喜欢
        • 2019-09-17
        • 1970-01-01
        • 1970-01-01
        • 2017-10-04
        • 1970-01-01
        • 2016-04-04
        • 2017-03-08
        • 1970-01-01
        相关资源
        最近更新 更多