对 createAsyncThunk 生成的动作创建者和参数的打字支持

问题描述 投票:0回答:3

我正在按照 Redux Essentials Tutorials 学习如何使用

createAsyncThunk
来生成 Thunk。在他们的例子中他们创建了一个像这样的thunk:

export const addNewPost = createAsyncThunk(
  'posts/addNewPost',
  async (initialPost) => { // Note: initialPost is an object with 3 props: title, content, user
    const response = await client.post('/fakeApi/posts', initialPost)
    return response.data
  }
)

他们在另一个文件中这样称呼它:

await dispatch(addNewPost({ title, content, user: userId }))

在我的项目中,我安装了打字稿和反应类型(

@types/react
)。即使代码是 JavaScript,这也可以让我从 VSCode IDE 获得正确类型的智能感知。然而,当我执行上述操作时,我看到:

输入需要 0 个参数,但得到一个,我的对象。将鼠标悬停在该方法上

addNewPost
我看到它不需要参数并返回异步操作。

如何让我的 IDE 和打字稿类型支持识别所需的正确参数?

我尝试了什么

尝试将一些 JSDOC 字符串添加到创建的

addNewPost
函数中,如下所示:

/**
 * addNewPost
 * @returns {(initialPost:{title:string, content:string, user: string}) => void} the returned action create takes an object as arg
 */
export const addNewPost = createAsyncThunk(
  'posts/addNewPost',
  async (initialPost) => {
    const response = await client.post('/fakeApi/posts', initialPost)
...

遵循另一个关于如何使用 JSDocs 描述返回函数的 Stack Overflow 建议。但这似乎不起作用。

大家有什么建议吗?

javascript reactjs redux redux-toolkit jsdoc
3个回答
1
投票

问题是 Redux 中默认的

Dispatch
类型只能理解
dispatch()
函数可以接受普通的操作对象。它知道 thunk 函数是可以传入的有效函数。

为了使此代码正常工作,您需要按照我们的说明设置商店并根据配置的所有实际中间件(通常包括 thunk 中间件)推断 dispatch

real
类型:

https://redux.js.org/tutorials/typescript-quick-start

然后,在应用程序的其他位置使用该

AppDispatch
类型,这样当您尝试发送某些内容时,TS 就会识别出 thunk 是可以传入的有效内容。

所以,通常:

// store.ts
const store = configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer
  }
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

// hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

// MyComponent.ts
import { useAppDispatch } from '../../app/hooks'

export function MyComponent() {
  const dispatch = useAppDispatch()

  const handleClick = () => {
    // Works now, because TS knows that `dispatch` is `AppDispatch`,
    // and that the type includes thunk handling
    dispatch(someThunk())
  }
}

此外,在您的具体情况下,您正在使用

createAsyncThunk
。您需要告诉 TS 其参数的类型,按照 https://redux-toolkit.js.org/usage/usage-with-typescript#createasyncthunk:

export const addNewPost = createAsyncThunk(
  'posts/addNewPost',
  async (initialPost: InitialPost) => { 
    // The actual `client` in the Essentials tutorial is plain JS
    // But, if we were using Axios, we could do:
    const response = await client.post<ResultPost>('/fakeApi/posts', initialPost)
    // If the `client` was written well, `.data` is of type `ResultPost`
    return response.data
  }
)

1
投票

我很幸运地将 JSDoc 修改为专门位于

payloadCreator
函数内的
createAsyncThunk
参数之上,如下所示:

export const addNewPost = createAsyncThunk(
  'posts/addNewPost',
  /**
   * Make POST request to API w. params and create a new record
   * @param {{content: string, title: string, user: string}} initialPost
   * @returns {Promise<{content: string, date: string, id: string, reactions: Object, title: string, user: string}>} returned data
   */
  async (initialPost) => {
    const response = await client.post('/fakeApi/posts', initialPost)
    // The response includes the complete post object, including unique ID
    return response.data
  }
)

当我更仔细地观察

createAsyncThunk
的工作原理时,我意识到为什么这更有意义,因为 createAsyncThunk 本身不返回这些值,它们是我们传递给它的函数的参数和返回类型。


0
投票

在 VSCode 上,我设法使用 IntelliSense(描述和参数名称)正确显示所有内容的唯一方法是执行以下操作:

/**
 * @callback MyAction
 * @param {string} testParam - A test param
 */

/**
 * Does something.
 * @type {MyAction}
 */

export const myAction = createAsyncThunk("MY-ACTION", async (testParam) => {
  // ...
});

相比之下,这就是我将 JSDoc 放在

payloadCreator
之上时得到的结果:

export const myAction = createAsyncThunk("MY-ACTION",
  /**
   * Does something.
   * @param {string} testParam - A test param
   */
  async (testParam) => {
  // ...
  }
);

© www.soinside.com 2019 - 2024. All rights reserved.