TypeScript类型推断

时间:2018-01-24 07:37:03

标签: typescript type-inference

在下面的代码中,我尝试创建一个类型安全的函数来访问给定输入的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<{}>)?
  2. 为什么TypeScript不能根据返回类型正确推断表达式的类型?
  3. Link to TypeScript's playground with the code.

2 个答案:

答案 0 :(得分:2)

让我们从解决方案开始:

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

为了使类型推断起作用,我们需要为TypeScript提供一个起点,在这种情况下,它是我们用来启动执行的函数。如果我们让获取方法通用T参数具有默认值(即{}),那么TypeScript将使用该类型来确定所有连接的函数调用,基本上是然后 getData 继承该默认类型。最后,当TypeScript到达必须验证最后一个函数签名( getData )和外部 fetchUser 签名之间的类型正确性时,它会发现冲突,因为与{}类型和 fetchUser 一起明确表明它适用于用户类型。

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

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

如果将鼠标悬停在 fetchUser 函数上,您将看到TypeScript从内部 fetch 函数签名中推断出User类型,并且仍然是Promise&lt;使用者&gt;

答案 1 :(得分:1)

对于您的第一个问题,TypeScript抱怨类型为Promise<{}>的原因是,如果您没有为返回promise的泛型函数指定类型,则默认为{{1} }。

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

我认为您可以在Promise<HttpResponse<{}>>中调用User时指定fetch类型,从而使其成功:

fetchUser

如果你直接回复return fetch<User>('https://...').then(getData); ,那么你正在寻找的推论就会奏效。类似的东西:

fetch

但是,由于您正在联系该调用,因此async function getValueAsync<T>(): Promise<T> { return null; } function testGetValueAsync(): Promise<User> { return getValueAsync(); } 调用中没有任何内容告诉TypeScript它返回的是什么类型。

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

fetch