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) => Case[]' is not assignable to parameter of type '(value: Response) => Case[] | PromiseLike<Case[]>'.
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
isPromise<Response>
- Return type of
Response.json
isPromise<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.