Home > Mobile >  How to cast a Promise<Response>?
How to cast a Promise<Response>?

Time:02-27

I use fetch to query some JSON data from an API.

The helper function I wrote returns a Promise<Response> (this is a simplified version)

const apiCall = (): Promise<Response> => fetch('http://the.api.com').then(r => r.json())

I then use it like this:

export class Case {
  Uuid?:       string
  Topic?:      string
  public constructor(init?:Partial<Case>) {
    Object.assign(this, init);
  }
}

callApi()
  .then(r => allCases.value = r.Data as Array<Case>) // the error is on this line
  .catch(() => {{}})

My problem: TypeScript reports an error:

TS2339: Property 'Data' does not exist on type 'Response'.

The program goes through successfully anyway, but I would like to understand this error and fix it (mostly to better understand TS in general).

I then tried to hint r with the expected type:

interface ApiResponse {
  Data: Array<Case>
}

callApi('/case', 'GET')
  .then((r: ApiResponse) => allCases.value = r.Data as Array<Case>)
  .catch(() => {{}})

This brings in two errors now:

TS2345: Argument of type '(r: ApiResponse) =&gt; Case[]' is not assignable to parameter of type '(value: Response) =&gt; Case[] | PromiseLike&lt;Case[]&gt;'.
Types of parameters 'r' and 'value' are incompatible.
Property 'Data' is missing in type 'Response' but required in type 'ApiResponse'.

ESLint: This assertion is unnecessary since it does not change the type of the expression. (@typescript-eslint/no-unnecessary-type-assertion)

How can I express the fact that what comes from my helper function should be treated as an Object (with a Data key)

CodePudding user response:

You can define callApi as follows:

const callApi = (): Promise<ApiResponse> => fetch('http://the.api.com').then(r => r.json())

Looking at the type definitions of node-fetch tells me:

  • Return type of fetch is Promise<Response>
  • Return type of Response.json is Promise<unknown>

So the return type of your callApi function is Promise<unknown> and not Promise<Response>.

Then this should work:

callApi().then(r => allCases.value = r.Data).catch(() => {{}})

Why this solution of yours doesn't work:

callApi('/case', 'GET')
    .then((r: ApiResponse) => allCases.value = r.Data as Array<Case>)
    .catch(() => {{}})

Here you are passing a wrongly-types callback function as an argument to then since the type of r is not ApiResponse but Response as you have typed it before. This results in a TS error.

  • Related