Ricerca nel sito web

reactjs - React Redux Typescript - come impostare i tipi?


Sto avendo difficoltà a impostare i tipi per questa funzione:

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);
            });
    };
};

dice che setCountries si aspettava 0 argomenti, ma ne ha ricevuto 1.

Ho provato a seguire diverse guide, come questa, ma non sono riuscito a farlo funzionare. Mi sono perso. Voglio qui eliminare tutti i tipi any e dare quelli veri.

Il negozio ha esportato:

export type RootState = ReturnType<typeof store.getState>;
export type AppState = ReturnType<typeof rootReducer>;
export type AppDispatch = typeof store.dispatch;

Ecco la fetta:

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;

Qualcuno può per favore aiutare?

Risposta n. 1

Ci sono alcuni problemi qui nel tuo codice che sono tutti correlati. Devi definire correttamente:

  1. Il tipo di dispatch nella tua funzione fetchCountries.
  2. Il tipo del payload per setCountries.
  3. Il tipo del tuo stato.
  4. Il tipo della tua risposta API.

Tipi errati o mancanti più in alto nella catena possono causare problemi più avanti. Ad esempio, quando ti ritrovi a impostare un tipo in un callback di .map() in questo modo:

array[1].map((el: any) => {

Significa che l'array stesso (array[1]) ha il tipo sbagliato. Quindi cerchiamo di capire dove sta andando storto.


1. Tipo di spedizione

@T.D. Stoneheart ha ragione. L'errore expected 0 arguments, but got 1 deriva dalla chiamata a dispatch(...), non dalla chiamata a setCountries(...).

La tua definizione dispatch:(() => void) dice che dispatch non prende argomenti. Questo è ovviamente incorretto.

La buona notizia è che hai già il tipo corretto da qualche altra parte nel tuo codice. È AppDispatch che hai esportato dal tuo file store.

export const fetchCountries = () => {
    return (dispatch: AppDispatch) => {

Questa correzione è sufficiente per risolvere tutti gli errori sottolineati in rosso. Ma ci sono altri errori e omissioni che potresti voler correggere.


2. Tipo di payload

Se non imposti esplicitamente il tipo per setCountries(state, action), allora il tipo del tuo payload diventa any. Questo va bene, ma non è l'ideale. Indica che "tutto va bene", il che può rendere difficile individuare problemi reali.

Per assegnare il tipo corretto all'azione, importa il tipo di utilità PayloadAction per redux toolkit:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

E usalo con il tipo del tuo payload, che è un array di paesi. Guardando il tuo thunk, questi sembrano essere string?

reducers: {
    setCountries(state, action: PayloadAction<string[]>) {
        state.countryList = action.payload;      
    },
},

3. Tipo di Stato

Ricorda come ho detto che any può nascondere problemi reali? Se hai seguito il passo 2, dovresti vederne uno adesso.

L'assegnazione di state.countryList=action.payload; sta dando un errore:

Il tipo 'string[]' non è assegnabile al tipo 'never[]'.

Il tuo state.countryList ha tipo never[] perché aveva un valore iniziale di [] e questo è tutto ciò che TypeScript conosce. Non sa che questo dovrebbe essere un array di ID di paesi. Puoi risolvere questo assegnando un tipo più accurato al tuo initialState.

Fai così:

const initialState = {
    countryList: [] as string[],
};

O questo:

interface SliceState { // can name it whatever
    countryList: string[];
}

const initialState: SliceState = {
    countryList: [],
};

Avere il tipo corretto qui renderà molto, molto più facile usare i dati che hai selezionato dal tuo stato perché ora RootState ha il tipo corretto per la proprietà countryList.


4. Tipo di risposta API

interface fetchedCountries {
    mergedArray?: [];
}

Questo tipo sta dicendo che il JSON dalla tua risposta è un oggetto che potrebbe avere una proprietà mergedArray che è un array vuoto. Tutto qui.

Non sono sicuro di come siano effettivamente i dati, ma forse qualcosa del genere?

interface Country {
    _id: string;
}

interface FetchedCountries {
    mergedArray: Country[];
}

Quindi ora non devi più usare (el: any) perché TypeScript sa già che el è un oggetto Country.

.then((jsonData: FetchedCountries) => {
    const countries = jsonData.mergedArray
        .map(el => el._id)
        .sort();
    dispatch(setCountries(countries));
})

Link del Playground di TypeScript

Risposta n. 2

In realtà, il problema risiede nel tipo di parametro della funzione che restituisce.

Hai restituito (dispatch: ((/* no parameters */) => void)) => {} ma hai chiamato dispatch(setCountries(countries)) che ha un argomento setCountries(countries). Impostare il numero corretto di parametri risolverà il problema, come return (dispatch: ((something: unknown) => void)) => {}.

Articoli correlati