title: Passing an AsyncThunkAction to unwrapResult
body: <p>I'm following the Redux Essentials tutorial and I've run into a problem in part 5, <a href="https://redux.js.org/tutorials/essentials/part-5-async-logic" rel="noreferrer">Async Logic and Data Fetching</a>. I'm using TypeScript even though TypeScript is not used in the tutorial because I'm trying to learn both Redux and TypeScript at once.</p>
  <p>In the section <a href="https://redux.js.org/tutorials/essentials/part-5-async-logic#checking-thunk-results-in-components" rel="noreferrer">Checking Thunk Results in Components</a>, I'm getting a type error when calling Redux's <code>unwrapResult</code> function that I have not been able to figure out.</p>
  <p>Here's the error:</p>
  <pre><code>TypeScript error in redux-essentials-example-app/src/features/posts/AddPostForm.tsx(34,22):
  Argument of type 'AsyncThunkAction&lt;Post, InitialPost, {}&gt;' is not assignable to parameter of type 'ActionTypesWithOptionalErrorAction'.
    Property 'payload' is missing in type 'AsyncThunkAction&lt;Post, InitialPost, {}&gt;' but required in type '{ error?: undefined; payload: any; }'.  TS2345
  
      32 |         setAddRequestStatus(&quot;pending&quot;);
      33 |         const result = await dispatch(addNewPost({ title, content, user: userId }));
    &gt; 34 |         unwrapResult(result);
         |                      ^
      35 |         setTitle(&quot;&quot;);
      36 |         setContent(&quot;&quot;);
      37 |         setUserId(&quot;&quot;);
  </code></pre>
  <p>Here is the full contents of my typed version of AddPostForm.tsx:</p>
  <pre><code>import React, { useState } from &quot;react&quot;;
  import { useDispatch, useSelector } from &quot;react-redux&quot;;
  import { unwrapResult } from &quot;@reduxjs/toolkit&quot;;
  
  import { RootState } from &quot;../../app/store&quot;;
  import { addNewPost } from &quot;./postsSlice&quot;;
  
  export default function AddPostForm() {
    const [title, setTitle] = useState(&quot;&quot;);
    const [content, setContent] = useState(&quot;&quot;);
    const [userId, setUserId] = useState(&quot;&quot;);
    const [addRequestStatus, setAddRequestStatus] = useState(&quot;idle&quot;);
  
    const dispatch = useDispatch();
    const users = useSelector((state: RootState) =&gt; state.users);
  
    const onTitleChanged = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
      setTitle(e.target.value);
    };
    const onContentChanged = (e: React.ChangeEvent&lt;HTMLTextAreaElement&gt;) =&gt; {
      setContent(e.target.value);
    };
    const onAuthorChanged = (e: React.ChangeEvent&lt;HTMLSelectElement&gt;) =&gt; {
      setUserId(e.target.value);
    };
  
    const canSave = [title, content, userId].every(Boolean) &amp;&amp; addRequestStatus === &quot;idle&quot;;
  
    const onSavePostClicked = async () =&gt; {
      if (canSave) {
        try {
          setAddRequestStatus(&quot;pending&quot;);
          const result = await dispatch(addNewPost({ title, content, user: userId }));
          unwrapResult(result);
          setTitle(&quot;&quot;);
          setContent(&quot;&quot;);
          setUserId(&quot;&quot;);
        } catch (err) {
          console.error(&quot;Failed to save the post: &quot;, err);
        } finally {
          setAddRequestStatus(&quot;idle&quot;);
        }
      }
    };
  
    const usersOptions = users.map(user =&gt; (
      &lt;option key={user.id} value={user.id}&gt;
        {user.name}
      &lt;/option&gt;
    ));
  
    return (
      &lt;section&gt;
        &lt;h2&gt;Add a new post&lt;/h2&gt;
        &lt;form&gt;
          &lt;label htmlFor=&quot;postTitle&quot;&gt;Post Title:&lt;/label&gt;
          &lt;input type=&quot;text&quot; id=&quot;postTitle&quot; name=&quot;postTitle&quot; value={title} onChange={onTitleChanged} /&gt;
          &lt;label htmlFor=&quot;postAuthor&quot;&gt;Author:&lt;/label&gt;
          &lt;select id=&quot;postAuthor&quot; value={userId} onChange={onAuthorChanged}&gt;
            &lt;option value=&quot;&quot;&gt;&lt;/option&gt;
            {usersOptions}
          &lt;/select&gt;
          &lt;label htmlFor=&quot;postContent&quot;&gt;Content:&lt;/label&gt;
          &lt;textarea id=&quot;postContent&quot; name=&quot;postContent&quot; value={content} onChange={onContentChanged} /&gt;
          &lt;button type=&quot;button&quot; onClick={onSavePostClicked} disabled={!canSave}&gt;Save post&lt;/button&gt;
        &lt;/form&gt;
      &lt;/section&gt;
    );
  }
  </code></pre>
  <p>And here is the full contents of my typed version of redux-essentials-example-app/src/features/posts/postsSlice.tsx:</p>
  <pre><code>import { createAsyncThunk, createSlice } from &quot;@reduxjs/toolkit&quot;;
  
  import { RootState } from &quot;../../app/store&quot;;
  import { client } from &quot;../../api/client&quot;;
  
  export interface PostState {
    posts: Post[],
    status: &quot;idle&quot; | &quot;loading&quot; | &quot;succeeded&quot; | &quot;failed&quot;,
    error: string | null,
  }
  
  export interface Post {
    id: string,
    date: string,
    title: string,
    content: string,
    user: string,
    reactions: Reactions,
  }
  
  export interface Reactions {
    thumbsUp: number,
    hooray: number,
    heart: number,
    rocket: number,
    eyes: number,
    [key: string]: number,
  }
  
  const initialState: PostState = {
    posts: [],
    status: &quot;idle&quot;,
    error: null,
  };
  
  export const fetchPosts = createAsyncThunk(&quot;posts/fetchPosts&quot;, async () =&gt; {
    const response = await client.get(&quot;/fakeApi/posts&quot;);
    return response.posts;
  });
  
  interface InitialPost {
    title: string,
    content: string,
    user: string,
  }
  
  export const addNewPost = createAsyncThunk&lt;Post, InitialPost&gt;(
    &quot;posts/addNewPost&quot;,
    async (initialPost) =&gt; {
      const response = await client.post(&quot;/fakeApi/posts&quot;, { post: initialPost });
      return response.post;
    }
  );
  
  const postsSlice = createSlice({
    name: &quot;posts&quot;,
    initialState,
    reducers: {
      postUpdated: (state, action) =&gt; {
        const { id, title, content } = action.payload;
        const existingPost = state.posts.find(post =&gt; post.id === id);
  
        if (existingPost) {
          existingPost.title = title;
          existingPost.content = content;
        }
      },
      reactionAdded: (state, action) =&gt; {
        const { postId, reaction } = action.payload;
        const existingPost = state.posts.find((post: Post) =&gt; post.id === postId);
        if (existingPost) {
          existingPost.reactions[reaction]++;
        }
      },
    },
    extraReducers: builder =&gt; {
      builder.addCase(fetchPosts.pending, (state) =&gt; {
        state.status = &quot;loading&quot;;
      });
      builder.addCase(fetchPosts.fulfilled, (state, action) =&gt; {
        state.status = &quot;succeeded&quot;;
        state.posts = state.posts.concat(action.payload);
      });
      builder.addCase(fetchPosts.rejected, (state, action) =&gt; {
        state.status = &quot;failed&quot;;
        if (action.error.message) {
          state.error = action.error.message;
        }
      });
      builder.addCase(addNewPost.fulfilled, (state, action) =&gt; {
        state.posts.push(action.payload);
      });
    },
  });
  
  export const { postUpdated, reactionAdded } = postsSlice.actions;
  
  export function selectAllPosts(state: RootState) {
    return state.posts.posts;
  }
  
  export function selectPostById(state: RootState, postId: string) {
    return state.posts.posts.find((post: Post) =&gt; post.id === postId);
  }
  
  export default postsSlice.reducer;
  </code></pre>
  <p>I looked at the source code of Redux Toolkit and the <code>ActionTypesWithOptionalErrorAction</code> type is not exported, so it seems that the object being passed to <code>unwrapResult</code> needs to be a certain shape rather than declared as a certain type. The type error says the <code>payload</code> property is missing, but it's definitely there if I comment out the <code>unwrapResult</code> call and instead inspect the object with <code>console.log(result)</code>. So it seems to be an issue of getting the types correct rather than a logical error in the code. How do I type this correctly?</p>