【问题标题】:Redux Thunk in TypeScriptTypeScript 中的 Redux Thunk
【发布时间】:2019-03-20 01:02:10
【问题描述】:

我试图更好地理解 ThunkDispatch 函数和 TypeScript。得到了使用 redux 和 thunk 的代码。

// This is redux-thunk source code
import { Middleware, Action, AnyAction } from "redux";

export interface ThunkDispatch<S, E, A extends Action> {
  <T extends A>(action: T): T;
  <R>(asyncAction: ThunkAction<R, S, E, A>): R;
}

export type ThunkAction<R, S, E, A extends Action> = (
  dispatch: ThunkDispatch<S, E, A>,
  getState: () => S,
  extraArgument: E
) => R;

===================

import { Action } from 'redux'
import { ThunkAction } from 'redux-thunk'
import { ThunkDispatch } from 'redux-thunk'

interface ReduxState {
  // redux states
}

type ThunkResult<R> = ThunkAction<R, ReduxState, undefined, Action>
type ReduxDispatch = ThunkDispatch<ReduxState, undefined, Action>

const loadAppData = (): ThunkResult<void> => async (dispatch, getState) => {
  // get app data
  dispatch(MyAction.getAppDataSuccess(17))
}

const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
  loadAppData: () => dispatch(loadAppData()),
})

我目前的理解:

export interface ThunkDispatch<S, E, A extends Action> {
  <T extends A>(action: T): T;
  <R>(asyncAction: ThunkAction<R, S, E, A>): R;
}

ThunkDispatch 是一个具有 2 个属性的接口,我们称它们为 A 和 B。A 是一个函数,其参数名为 action,类型为 T,并返回类型为 T 的内容。同样,对于 B,它是一个函数,其参数名为 asyncAction,类型为 ThunkAction&lt;R, S, E, A&gt;,并返回类型为 R 的内容。

问题 &lt;T extends A&gt;&lt;R&gt; 部分是否只是暗示新的泛型类型?

我目前的理解:

const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
  loadAppData: () => dispatch(loadAppData()),
})

dispatch作为参数是ReduxDispatch的一种类型,它是一个具有2个属性函数的接口。

loadAppData 是一个返回ThunkResult&lt;void&gt; 类型的函数,它等价于ThunkAction&lt;Void, ReduxState, undefined, Action&gt;。如果我们将这些类型放入ThunkAction 定义中,它会匹配async (dispatch, getState) =&gt; { ... } 的签名

问题 mapDispatchToPropsloadAppData() 中的 dispatch(loadAppData()) 返回一个 ThunkResult&lt;void&gt;,它本质上是一个函数。 dispatch 只是一个带有 2 个属性函数的接口,那么这个语法对我来说没有意义,interface(func)

如果我误解了什么,请指出!谢谢

【问题讨论】:

  • “ThunkDispatch 是一个具有 2 个属性的接口”——这就是你感到困惑的原因。 ThunkDispatch 是一个有 2 个重载的函数。一个接受action: T,另一个接受asyncAction: ThunkAction&lt;R, S, E, A&gt;
  • 谢谢@zerkms 你能给一个链接来解释这个语法吗?当我谷歌 Typescript 函数重载时,他们都没有提到这个语法
  • 而且很有趣,为什么ThunkDispatch 是一个函数,而不是一个接口?
  • ThunkDispatch - 这是一个描述函数的接口

标签: typescript redux redux-thunk


【解决方案1】:

我个人在 TS 手册中找不到完整解释接口函数重载的地方。

所有可用的是:

  1. Interfaces :: Function types
  2. Function overloads

如果我没记错你提供的声明

export interface ThunkDispatch<S, E, A extends Action> {
  <T extends A>(action: T): T;
  <R>(asyncAction: ThunkAction<R, S, E, A>): R;
}

可以以其他方式实现为以下两种函数类型的联合:

type ThunkDispatch<S, E, A extends Action> = (<T extends A>(action: T) => T) | (<R>(asyncAction: ThunkAction<R, S, E, A>) => R);

type ThunkDispatch<S, E, A extends Action> =
    | (<T extends A>(action: T) => T)
    | (<R>(asyncAction: ThunkAction<R, S, E, A>) => R);

【讨论】:

    【解决方案2】:

    虽然这是一个迟到的回复,但值得将它作为对这个问题的回答。来自Redux Usage with Typescript

    Redux Thunk 是一种常用的中间件,用于编写与 Redux 存储交互的同步和异步逻辑。随意在此处查看其文档。 thunk 是一个函数,它返回另一个接受参数 dispatch 和 getState 的函数。 Redux Thunk 有一个内置类型 ThunkAction,我们可以使用它来定义这些参数的类型:

    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()
        })
      )
    }
    

    【讨论】: