Reputation: 199
I'm having hard time setting the types for this function:
interface fetchedCountries {
mergedArray?: [];
}
export const fetchCountries = () => {
return (dispatch:(() => void)) => {
console.log(dispatch)
fetch(countryListJsonFile)
.then((response) => response.json())
.then((jsonData: fetchedCountries) => {
const array = Object.entries(jsonData)[0];
const countries = array[1].map((el: any) => {
return el._id;
}).sort();
dispatch(setCountries(countries));
})
.catch(function (err) {
console.error(err);
});
};
};
it says that setCountries expected 0 arguments, but got 1
.
I've tried to follow different guides, such as this, but I couldn't make it work.
I got lost. I want here to get rid of all the any
types, and give the real ones.
The store has exported:
export type RootState = ReturnType<typeof store.getState>;
export type AppState = ReturnType<typeof rootReducer>;
export type AppDispatch = typeof store.dispatch;
Here is the slice:
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
countryList: [],
};
const slice = createSlice({
name: 'countryList',
initialState,
reducers: {
setCountries(state, action) {
state.countryList = action.payload;
},
},
});
export const { setCountries } = slice.actions;
export default slice.reducer;
Can anyone please help?
Upvotes: 3
Views: 2833
Reputation: 901
Actually, the problem lies in the parameter type of the returning function.
You returned (dispatch: ((/* no parameters */) => void)) => {}
but you called dispatch(setCountries(countries))
which has one argument setCountries(countries)
. Setting correct number of parameters will fix, like return (dispatch: ((something: unknown) => void)) => {}
.
Upvotes: 1
Reputation: 42298
There are a few issues here in your code are all related. You need to properly define:
dispatch
in your fetchCountries
function.payload
for setCountries
.Incorrect or missing types higher up in the chain can cause issues further down. For example, when you find yourself setting a type in a .map()
callback like this:
array[1].map((el: any) => {
It means that the array itself (array[1]
) has the wrong type. So let's figure out where it's going wrong.
@T.D. Stoneheart is correct. The expected 0 arguments, but got 1
error comes from calling dispatch(...)
, not from calling setCountries(...)
.
Your definition dispatch:(() => void)
says that dispatch
does not take any arguments. This is obviously incorrect.
The good news is that you already have the correct type elsewhere in your code. It is the AppDispatch
which you exported from your store file.
export const fetchCountries = () => {
return (dispatch: AppDispatch) => {
This fix is enough to resolve all red-underlined errors. But there are some other mistakes and omissions that you may want to fix.
If you don't explicitly set the type for setCountries(state, action)
, then your payload type becomes any
. This is fine, but not ideal. It says that "anything goes" which can make it hard to see genuine problems.
To assign the correct type to the action, import the PayloadAction
utility type for redux toolkit:
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
And use it with the type of your payload, which is an array of countries. Looking at your thunk, these seem to be string
?:
reducers: {
setCountries(state, action: PayloadAction<string[]>) {
state.countryList = action.payload;
},
},
Remember how I said that any
can hide genuine problems? If you followed step 2 then you should be seeing one of those now.
The assignment of state.countryList = action.payload;
is giving an error:
Type 'string[]' is not assignable to type 'never[]'.
Your state.countryList
has type never[]
because it had an initial value of []
and that's all that TypeScript knows. It doesn't know that this is supposed to be an array of country ids. You can fix that by assigning a more accurate type to your `initialState.
Either do this:
const initialState = {
countryList: [] as string[],
};
Or this:
interface SliceState { // can name it whatever
countryList: string[];
}
const initialState: SliceState = {
countryList: [],
};
Having a correct type here will make it much, much easier to use data that you've selected from your state because now RootState
has the correct type for the countryList
property.
interface fetchedCountries {
mergedArray?: [];
}
This type is saying that the JSON from your response is an object which maybe has a property mergedArray
which is an empty array. That's it.
I'm not sure what the actual data looks like, but perhaps something like this?
interface Country {
_id: string;
}
interface FetchedCountries {
mergedArray: Country[];
}
So now you don't need to use (el: any)
because TypeScript already knows that el
is a Country
object.
.then((jsonData: FetchedCountries) => {
const countries = jsonData.mergedArray
.map(el => el._id)
.sort();
dispatch(setCountries(countries));
})
Upvotes: 1