Flow type checking for Axios
Type checking with Flow is a nice addition to your code. Unfortunately, it is not so intuitive to use Flow with libraries like Axios. The main problem is lack of easily available usage examples.
Problem
Using Axios type annotations $AxiosXHR
and $AxiosXHRConfig
may result in error messages similar to this:
Cannot call resolve with result bound to result because string [1] is incompatible with object type [2] in type argument T [3]
or this:
Cannot call resolve with result bound to result because object type [1] is incompatible with string [2] in type argument R [3].
What are T
and R
and how to fix that?
Solution
If you would like to find out the answer yourself you will have to read the source code of Axios Flow implementation. The code is not so complicated if you have some experience with Flow types, but for newcomers it looks cryptic (at best).
Moving forward...
$AxiosXHR
is defined as $AxiosXHR<T, R=T>
which means that we have to provide at least one argument T
and optionally another R
.
T
- input data Type, should be a type ofdata
parameter in your Axios requestR
- Response type, should define expected type for a response
As you may noticed R
is optional and equals T
by default which is useful especially when dealing with no request data (e.g. all GET
queries) or no response data (e.g. POST
query with just 200 OK
as a response).
Example
As usual we have to begin with // @flow
declaration, import of Axios library and appropriate type definitions:
// @flow
import axios from "axios";
import type { $AxiosXHR } from "axios";
Let's define expected Axios response structure type:
export type RateLimit = {
limit: number,
remaining: number,
reset: number,
};
type RateLimitResponse = {
resources: {
core: RateLimit,
search: RateLimit,
graphql: RateLimit,
},
rate: RateLimit,
};
Now it's time for a "magical" $AxiosXHR
type annotation:
const getRateLimit = async (): Promise<$AxiosXHR<RateLimitResponse>> =>
axios(`https://api.github.com/rate_limit`);
We know that Github API endpoint /rate_limit
is going to return something which should match RateLimitResponse
. As we don't have any input data type there is no need to define more than one $AxiosXHR
parameter (R
equals T
by default).
What is more, we know that async
function should return a promise, thus we wrap returned type with Promise<....>
.
Now we can use Axios with Flow typings.
NOTE As mentioned by @Joey M. you may replace:
Promise<$AxiosXHR<RateLimitResponse>>
with
AxiosPromise<RateLimitResponse>
It's a hand wrapper which simplifies typings a bit. Of course it has to be imported before usage: import type { AxiosPromise } from 'axios';
Another example
Let say we have an API endpoint http://your-api-enpoint.test
which will respond with string OK
to every POST request with JSON data
body: { getStatus: true }
.
In this case Axios Flow typing for request is going to look like this:
type StatusRequest = {
getStatus: boolean,
};
const getStatus = async (): AxiosPromise<StatusRequest, string> =>
axios({
method: "post",
data: { getStatus: true },
url: "http://your-api-enpoint.test",
});
That's all?
Unfortunately, I don't know yet if it is possible to add Flow typings without wrapping Axios call in a wrapper function.
Ideally something like this might be possible:
const response: $AxiosXHR<RateLimitResponse> = await axios(
`https://api.github.com/rate_limit`,
);