Search code examples
reactjstypescriptreduxredux-toolkit

Getting the Error when I get selectors from createEntityAdapter in Typescript


While developing a simple pet project, I faced an error, without knowing how to fix it. I am new to Typescript, and judging by a message error the mistake is in TS. The error message appears after adding this snippet into the file 'apiSlice.ts'.

export const { selectAll: selectAllPizzas } = pizzasAdapter.getSelectors(
    state => selectPizzasData(state) ?? initialState
)

The error text looks like this:

ERROR in src/features/api/apiSlice.ts:44:31
TS2345: Argument of type 'unknown' is not assignable to parameter of type '{ api: CombinedState<{ getPizzas: QueryDefinition<void, BaseQueryFn<string | FetchArgs, unknown,
 FetchBaseQueryError, {}, FetchBaseQueryMeta>, never, PizzaResponseType[], "api">; }, never, "api">; }'.
    42 | //
    43 | export const { selectAll: selectAllPizzas } = pizzasAdapter.getSelectors(
  > 44 |     state => selectPizzasData(state) ?? initialState
       |                               ^^^^^
    45 | )
    46 |

The whole file: (Pay attention to the last three rows)

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { createEntityAdapter, createSelector } from '@reduxjs/toolkit'

const pizzasAdapter = createEntityAdapter()
const initialState = pizzasAdapter.getInitialState()

interface PizzaResponseType {
    id: string
    name: string
    image: string
    price: number
    currencySign: string
    popularityPoint: number
    type: string
    description: string
    spec: string
}
export const apiSlice = createApi({
    reducerPath: 'api',
    baseQuery: fetchBaseQuery({ baseUrl: '' }),
    endpoints: builder => ({
        getPizzas: builder.query<PizzaResponseType[], void>({
            query: () => '/pizzas',
            transformResponse: (responseData: PizzaResponseType[]) => {
                pizzasAdapter.setAll(initialState, responseData)
                return responseData
            },
        }),
    }),
})

export const { useGetPizzasQuery } = apiSlice

export const selectPizzasResult = apiSlice.endpoints.getPizzas.select()

// console.log(selectPizzasResult)

export const selectPizzasData = createSelector(
    selectPizzasResult,
    pizzasResult => pizzasResult.data
)
//
export const { selectAll: selectAllPizzas } = pizzasAdapter.getSelectors(
    state => selectPizzasData(state) ?? initialState
)

The RootState was imported from the store.ts file, where I configured the store as it was witten in the Redux Toolkit documentation. The store.ts file:

const store = configureStore({
    reducer: {
        pizzas:pizzaSlice,
        [apiSlice.reducerPath]: apiSlice.reducer,
    },
    middleware: getDefaultMiddleware => getDefaultMiddleware().concat(apiSlice.middleware),
})
export type RootState = ReturnType<typeof store.getState>
export default store

That imported RootState type was inserted for the state in the parameter:

export const { selectAll: selectAllPizzas } = pizzasAdapter.getSelectors(
    (state: RootState) => selectPizzasData(state) ?? initialState
)

and this change does nothing. The error appears anyway:

ERROR in src/features/api/apiSlice.ts:46:5
TS2345: Argument of type '(state: RootState) => EntityState<unknown> | PizzaResponseType[]' is not assignable to parameter of type '(state: { pizzas: EntityState<unknown>; api: CombinedState<{ getPizzas: Query
Definition<void, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, FetchBaseQueryMeta>, never, PizzaResponseType[], "api">; }, never, "api">; }) => EntityState<...>'.
  Type 'EntityState<unknown> | PizzaResponseType[]' is not assignable to type 'EntityState<unknown>'.
    Type 'PizzaResponseType[]' is missing the following properties from type 'EntityState<unknown>': ids, entities
    44 |
    45 | export const { selectAll: selectAllPizzas } = pizzasAdapter.getSelectors(
  > 46 |     (state: RootState) => selectPizzasData(state) ?? initialState
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    47 | )

How to fix it?

In case you want to run the pet project. Follow this link:https://github.com/AlexKor-5/ReactPizzaApp_Ts/tree/27028d4275fef75a70eb6b0b4b129e5bf5997e78 (but change the end of the apiSlice file so it corresponds to the file which is shown on the current page of Stack Overflow). (src/features/api/apiSlice.ts )

Also when I write <EntityState<PizzaResponseType> how it is supposed to be. Look at the example:

getPizzas: builder.query<EntityState<PizzaResponseType>, void>({
            query: () => '/pizzas',
            transformResponse: (responseData: PizzaResponseType[]) => {
                return pizzasAdapter.setAll(pizzaInitialState,responseData)
            },
        }),

I get another error:

TS2322: Type '(responseData: IPizzaType[]) => EntityState<unknown>' is not assignable to type '(baseQueryReturnV
alue: unknown, meta: FetchBaseQueryMeta | undefined, arg: void) => EntityState<IPizzaType> | Promise<EntityState
<IPizzaType>>'.
  Type 'EntityState<unknown>' is not assignable to type 'EntityState<IPizzaType> | Promise<EntityState<IPizzaTyp
e>>'.
    Type 'EntityState<unknown>' is not assignable to type 'EntityState<IPizzaType>'.
      Type 'unknown' is not assignable to type 'IPizzaType'.
    28 |         getPizzas: builder.query<EntityState<IPizzaType>, void>({
    29 |             query: () => '/pizzas',
  > 30 |             transformResponse: (responseData: IPizzaType[]) => {
       |             ^^^^^^^^^^^^^^^^^
    31 |                 return pizzasAdapter.setAll(pizzaInitialState, responseData)
    32 |             },
    33 |         }),

What is wrong again?


Solution

  • Following on from @phry 's initial response, I think the issue is your transformResponse function:

                transformResponse: (responseData: PizzaResponseType[]) => {
                    pizzasAdapter.setAll(initialState, responseData)
                    return responseData
                },
    

    That code has a couple problems:

    • You're returning the original responseData, which is still a PizzaResponseType[]. That tells TS that the result is also a PizzaResponseType[], when what it should be is an EntityState<Pizza>.
    • In order to make that happen, you need to return the value from pizzasAdapter.setAll() instead.