Redux Toolkit w/ TypeScript: how can I properly type the return value from an async thunk

Viewed 2270

I have a async thunk like this

export const updateIndexingConfig = createAsyncThunk(
  "settings/updateIndexingConfig",
  (config: UpdateIndexingConfigurationRequest) => {
    return sdkClient.updateIndexingConfiguration(config).promise();
  }
);

the update request can return an error message if there is any. The updateIndexingConfiguration.promise() is going to return a promise. And it is dispatched when user click on this button

<Button
  onClick={async () => {
    if (!isFormValid()) return;
    const updateIndexingConfigResponse = await dispatch(
      updateIndexingConfig(constructUpdateIndexingConfigRequest(indexingConfig))
    );
    if(updateIndexingConfigResponse.error) {
      // ... show error banner 
    } else {
      window.location.href = "#/settings/";
    }
  }}
>
  Update
</Button>;

TypeScript compiler is giving me this error on this line if(updateIndexingConfigResponse.error) saying that

Property 'error' does not exist on type 'AsyncThunkAction<any, UpdateIndexingConfigurationRequest, {}>'.

I think it is due to the SDK doesn't have the response type defined. but by reading its doc I know the response can have an error message when something goes wrong. so I quickly made one myself

interface UpdateIndexingConfigurationResponse {
  error?: {
    message: string;
  };
  [key: string]: any;
}

and I added it at the thunk

export const updateIndexingConfig = createAsyncThunk(
  "settings/updateIndexingConfig",
  (config: UpdateIndexingConfigurationRequest): UpdateIndexingConfigurationResponse => {
    return sdkClient.updateIndexingConfiguration(config).promise();
  }
);

However the compiler is still not happy about it when I access error on the the returned response from the dispatch.

Property 'error' does not exist on type 'AsyncThunkAction<UpdateIndexingConfigurationResponse, UpdateIndexingConfigurationRequest, {}>'.

Not sure what I am missing here. How can I properly type the response in this case?

Also a minor question, the TS compiler also yells to me at await dispatch(updateIndexingConfig(...)), saying that

'await' has no effect on the type of this expression.ts(80007)

but I know it indeed has effect. it does await in this case

Btw please don't question whether or not the code works, or even if sdkClient.updateIndexingConfiguration(config).promise() returns a promise or not, I tested it and I know it works. It is just the typing is missing and that is my question.

2 Answers

Your dispatch does not take types for thunks into account and thus the return type is typed incorrectly. Please use the actual Dispatch type from the store as decsribed in the documentation:

import { configureStore } from '@reduxjs/toolkit'
import { useDispatch } from 'react-redux'
import rootReducer from './rootReducer'

const store = configureStore({
  reducer: rootReducer
})

export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types

It looks to me like your inner function may not be returning a Promise, which it needs to for createAsyncThunk to work.

Related