如何在 Typescript 中使用 redux-thunk 使用 ThunkAction 正确键入 thunk? [英] How to properly type a thunk with ThunkAction using redux-thunk in Typescript?

查看:86
本文介绍了如何在 Typescript 中使用 redux-thunk 使用 ThunkAction 正确键入 thunk?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Typescript 对我的 redux-thunk 代码进行类型检查.

来自 Redux 的官方文档:

我们使用提供的 dispatch 函数来触发我们关心的下一个动作 - 所以在时间方面唯一重要的是在异步函数内部我们正在等待某些事情.Redux-thunk 内部没有对这个函数的结果做任何事情.这里有一个很好的解释器,解释了 thunk 如何在幕后工作(只需要预览):

https://frontendmasters.com/courses/rethinking-async-js/synchronous-and-asynchronous-thunks/

第二 - TState是的 - 这是整个商店状态类型

第三个 - TExtraThunkARg您可以添加自己的自定义额外参数,该参数在 dispatch 和 getState 之后传递到 thunk.这默认为未知,因为除非您明确提供它,否则不清楚它将是什么.这是类型安全的,因为尝试与未知参数交互将导致编译时错误.

更多信息:https://github.com/reduxjs/redux-thunk#injecting-a-custom-argument

第四 - TBasicAction

这是一种操作类型.动作是最基本的动作类型——其中每个 type 属性都是一个纯字符串.您可以选择提供自己的更具体的类型 - 即 type MyActionType = 'FOO_ACTION' |'BAR_ACTION' 用于进一步的类型安全/缩小.然后,您可以将其用作操作.

I'm trying to type check my redux-thunk code with Typescript.

From the official docs of Redux: Usage with Redux Thunk, we get this example:

// src/thunks.ts

import { Action } from 'redux'
import { sendMessage } from './store/chat/actions'
import { RootState } from './store'
import { ThunkAction } from 'redux-thunk'

export const thunkSendMessage = (
  message: string
): ThunkAction<void, RootState, unknown, Action<string>> => async dispatch => {
  const asyncResp = await exampleAPI()
  dispatch(
    sendMessage({
      message,
      user: asyncResp,
      timestamp: new Date().getTime()
    })
  )
}

function exampleAPI() {
  return Promise.resolve('Async Chat Bot')
}

To reduce repetition, you might want to define a reusable AppThunk type once, in your store file, and then use that type whenever you write a thunk:

export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>

QUESTION

I'm not fully understanding the use of the ThunkAction type:

ThunkAction<void, RootState, unknown, Action<string>>

There are 4 type params, right?

1st - void

This is the return type of the thunk, right? Shouldn't it be Promise<void>, since it's async?

2nd - RootState

It's the full state shape, right? I mean, it's not a slice, but the full state.

3rd - unknown

Why is this unknown? What is this?

4th - Action<string>

Also didn't understand this. Why is Action<T> taking a string as a parameter? Should it always be string? Why is it?

解决方案

From the typings at https://github.com/reduxjs/redux-thunk/blob/d28ab03fd1d2dd1de402928a9589857e97142e09/src/index.d.ts

/**
 * A "thunk" action (a callback function that can be dispatched to the Redux
 * store.)
 *
 * Also known as the "thunk inner function", when used with the typical pattern
 * of an action creator function that returns a thunk action.
 *
 * @template TReturnType The return type of the thunk's inner function
 * @template TState The redux state
 * @template TExtraThunkARg Optional extra argument passed to the inner function
 * (if specified when setting up the Thunk middleware)
 * @template TBasicAction The (non-thunk) actions that can be dispatched.
 */
export type ThunkAction<
  TReturnType,
  TState,
  TExtraThunkArg,
  TBasicAction extends Action
> = (
  dispatch: ThunkDispatch<TState, TExtraThunkArg, TBasicAction>,
  getState: () => TState,
  extraArgument: TExtraThunkArg,
) => TReturnType;

First - TReturnType

Here we don't care about the return type - we're not waiting for the result of the thunk anyway. In TS it's ok to assign any function to a void signature, as it's not going to hurt type safety. Here's an example showing that I can assign various async/non-async functions to a void function signature:

We use the provided dispatch function to trigger the next action we care about - so the only thing that matters in terms of timing is that internally to the async function we are awaiting certain things. Redux-thunk internally is not doing anything with the result of this function. Here's a great explainer on how thunks work under the hood (just the preview is necessary):

https://frontendmasters.com/courses/rethinking-async-js/synchronous-and-asynchronous-thunks/

Second - TState Yep - this is the whole store state type

Third - TExtraThunkARg You can add your own custom extra argument that gets passed into the thunk after dispatch and getState. This defaults to unknown, as unless you explicitly provide it then it's not clear what it will be. This is type safe, as trying to interact with an unknown argument will lead to compile time errors.

More here: https://github.com/reduxjs/redux-thunk#injecting-a-custom-argument

Fourth - TBasicAction

This is an action type. Action is the most basic type of action - where every type property is a plain string. Optionally you can provide your own more specific types - i.e type MyActionType = 'FOO_ACTION' | 'BAR_ACTION' for further type safety/narrowing. You would then use this as Action.

这篇关于如何在 Typescript 中使用 redux-thunk 使用 ThunkAction 正确键入 thunk?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆