reactjs - React Redux Typescript - hvordan sette typer?
Jeg har problemer med å sette typene for denne funksjonen:
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);
});
};
};
det står at setCountries forventet 0 argumenter, men fikk 1.
Jeg har prøvd å følge forskjellige guider, som denne, men jeg klarte ikke å få det til å fungere. Jeg gikk meg vill. Jeg vil her bli kvitt alle any-typene og gi de riktige.
Butikken har eksportert:
export type RootState = ReturnType<typeof store.getState>;
export type AppState = ReturnType<typeof rootReducer>;
export type AppDispatch = typeof store.dispatch;
Her er skiven:
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;
Kan noen vennligst hjelpe?
Svar #1
Det er noen få problemer her i koden din som alle henger sammen. Du trenger å definere riktig:
- Typen på
dispatchi dinfetchCountries-funksjon. - Typen til
payloadforsetCountries. - Typen til staten din.
- Typen på API-responsen din.
Feil eller manglende typer høyere opp i kjeden kan forårsake problemer lenger ned. For eksempel, når du finner deg selv i å sette en type i en .map()-callback slik:
array[1].map((el: any) => {
Det betyr at selve arrayet (array[1]) har feil type. Så la oss finne ut hvor det går galt.
1. Utsendelsestype
@T.D. Stoneheart har rett. Feilen expected 0 arguments, but got 1 kommer fra å kalle dispatch(...), ikke fra å kalle setCountries(...).
Din definisjon dispatch:(() => void) sier at dispatch ikke tar noen argumenter. Dette er åpenbart feil.
Den gode nyheten er at du allerede har riktig type et annet sted i koden din. Det er AppDispatch som du eksporterte fra din store-fil.
export const fetchCountries = () => {
return (dispatch: AppDispatch) => {
Denne løsningen er nok til å rette alle feil markert med rødt understrek. Men det er noen andre feil og utelatelser som du kanskje vil rette.
2. Nyttelasttype
Hvis du ikke eksplisitt setter typen for setCountries(state, action), vil payload-typen din bli any. Dette er greit, men ikke ideelt. Det sier at "alt går", noe som kan gjøre det vanskelig å se ekte problemer.
For å tilordne riktig type til handlingen, importer PayloadAction-verktøytypen for Redux Toolkit:
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
Og bruk det med typen til nyttelasten din, som er et array av land. Ser man på thunk-en din, ser disse ut til å være string?:}
reducers: {
setCountries(state, action: PayloadAction<string[]>) {
state.countryList = action.payload;
},
},
3. Statstype
Husk hvordan jeg sa at any kan skjule ekte problemer? Hvis du fulgte trinn 2, bør du nå se en av dem.
Tildelingen av state.countryList=action.payload; gir en feil:
Type 'string[]' kan ikke tilordnes til type 'never[]'.
Din state.countryList har typen never[] fordi den hadde en startverdi på [] og det er alt TypeScript vet. Den vet ikke at dette skal være et array av land-IDer. Du kan fikse det ved å tilordne en mer nøyaktig type til din initialState.
Enten gjør dette:
const initialState = {
countryList: [] as string[],
};
Eller dette:
interface SliceState { // can name it whatever
countryList: string[];
}
const initialState: SliceState = {
countryList: [],
};
Å ha riktig type her vil gjøre det mye, mye enklere å bruke dataene du har valgt fra tilstanden din, fordi RootState nå har riktig type for countryList-egenskapen.
4. API-responstype
interface fetchedCountries {
mergedArray?: [];
}
Denne typen sier at JSON-en fra svaret ditt er et objekt som kanskje har en egenskap mergedArray som er et tomt array. Det er alt.
Jeg er ikke sikker på hvordan de faktiske dataene ser ut, men kanskje noe som dette?
interface Country {
_id: string;
}
interface FetchedCountries {
mergedArray: Country[];
}
Så nå trenger du ikke å bruke (el: any) fordi TypeScript allerede vet at el er et Country-objekt.
.then((jsonData: FetchedCountries) => {
const countries = jsonData.mergedArray
.map(el => el._id)
.sort();
dispatch(setCountries(countries));
})
TypeScript-lekespilllenke
Svar #2
Faktisk ligger problemet i parameter-typen til den returnerende funksjonen.
Du returnerte (dispatch: ((/* ingen parametere */) => void)) => {} men du kalte dispatch(setCountries(countries)) som har ett argument setCountries(countries). Å sette riktig antall parametere vil løse det, for eksempel return (dispatch: ((something: unknown) => void)) => {}.
