javascript 对ASyncThunk生成的动作创建器和参数的类型支持

swvgeqrz  于 5个月前  发布在  Java
关注(0)|答案(3)|浏览(91)

我一直在沿着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 }))


在我的项目中,我安装了typescript和react类型(@types/react)。即使代码是JavaScript,这也让我从VSCode IDE中获得了正确的类型。然而,当我这样做时,我看到:


的数据
类型化需要0个参数,但得到了一个,我的对象。将鼠标悬停在方法addNewPost上,我看到它没有接受参数,并返回了一个blog操作。



我怎样才能让我的IDE和typescript打字支持识别所需的正确参数?

我努力

尝试向创建的addNewPost函数添加一些JSDOC字符串,如下所示:

/**
 * 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)
...


下面是另一个Stack Overflow suggestion关于如何使用JSign来描述返回的函数。但这似乎不起作用。
有人有什么建议吗?

nkhmeac6

nkhmeac61#

问题是Redux的默认Dispatch类型只知道dispatch()函数可以接受普通操作对象。它不知道形实转换函数是可以传入的有效对象。
为了使这段代码正确工作,你需要按照我们的说明来设置存储,并根据配置的所有实际中间件来推断dispatch的 * 真实的 * 类型,其中通常包括形实转换中间件:
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
  }
)

hivapdat

hivapdat2#

我很幸运地修改了JSDoc,使其在createAsyncThunk函数中的payloadCreator参数之上,如下所示:

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的工作方式时,我意识到为什么这更有意义,因为AsyncThunk本身并不返回这些值,它们是我们传递给它的函数的参数和返回类型。

6g8kf2rb

6g8kf2rb3#

在VSCode上,我设法让所有内容都正确显示的唯一方法是使用智能感知(描述和参数名称),方法如下:

/**
 * @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) => {
  // ...
  }
);

相关问题