首页 > 解决方案 > Typescript 显然为分派的 Thunk 推断出错误的类型

问题描述

完整的工作代码框示例 在这里

我声明了一个简单的动作类型和一个调度它的异步 thunk:

type ActionType = { type: "foo"; v: number };

const FooThunk: ThunkAction<Promise<ActionType>, any, any, ActionType> = (dispatch): Promise<ActionType>
=> {
  return new Promise<number>((resolve) => {
    setTimeout(() => {
      resolve(42);
    }, 100);
  }).then((v: number) => {
    return dispatch({ type: "foo", v });
  });
};

现在的问题是当我调用dispatch(FooThunk). Typescript 认为类型是ThunkAction<Promise<ActionType>, any, any, ActionType>并抱怨(在沙箱的第 38 行)并显示以下消息:

'ThunkAction<Promise<ActionType>, any, any, ActionType>' is missing the following properties from type 'Promise<ActionType>': then, catch, [Symbol.toStringTag]ts(2739)

但是,当我记录在运行时获得的值(代码框的第 48 行)时,我清楚地看到它是一个Promise. 在 StackOverflow 上搜索我发现了相互矛盾的答案。 这个答案说调度一个 thunk 会返回 thunk 本身。而这个答案表明调度一个 thunk 会返回一个 Promise。

Typescript 的类型系统似乎说调度 thunk 的类型与 thunk 本身相同。但是在运行时我得到一个 Promise 对象。我错过了什么?

仅出于完整性目的,我附加了您将找到沙箱的代码(上面提供的链接):

import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import { initialState, rootReducer } from "./rootReducer";
import "./styles.css";

import { ThunkDispatch as Dispatch, ThunkAction } from "redux-thunk";
import { connect, ConnectedProps } from "react-redux";

import { applyMiddleware } from "redux";

import thunk from "redux-thunk";

const store = createStore(
  rootReducer /* preloadedState, */,
  applyMiddleware(thunk)
);

//const store = createStore(rootReducer, initialState);

type ActionType = { type: "foo"; v: number };

const FooThunk: ThunkAction<Promise<ActionType>, any, any, ActionType> = (
  dispatch
): Promise<ActionType> => {
  return new Promise<number>((resolve) => {
    setTimeout(() => {
      resolve(42);
    }, 100);
  }).then((v: number) => {
    return dispatch({ type: "foo", v });
  });
};

const mapDispatchToProps = (dispatch: Dispatch<any, any, any>) => {
  return {
    dispatchFooThunk: (): Promise<ActionType> => dispatch(FooThunk)
  };
};
const connector = connect(null, mapDispatchToProps);

type PropsFromRedux = ConnectedProps<typeof connector>;

class FooComponent_ extends React.Component<PropsFromRedux> {
  componentDidMount() {
    const p = this.props.dispatchFooThunk();
    console.log(p); // if you examine log output you see clearly that this is a PROMISE !
  }
  render() {
    return <div>foo</div>;
  }
}

const FooComponent = connector(FooComponent_);

class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <FooComponent />
      </Provider>
    );
  }
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

标签: reactjstypescriptreduxredux-thunk

解决方案


thunk 的返回值是 thunk 操作本身的返回值。结果:如果它是一个异步函数,它会返回一个 Promise。

普通Dispatch类型虽然不知道如何处理 thunk。如果您使用的是 redux 工具包,则此文档部分描述了如何使用useDispatch从商店配置推断的 Dispatch 类型正确键入您的钩子。如果你使用的是普通的 redux,你可以使用ThunkDispatch类型。react-redux 文档的这一部分描述了在这种情况下如何键入你的useDispatch钩子。

PS:在你的具体情况下,你ThunkDispatch<any, any, any>的太笼统了。最后一个any会太热切地匹配。尝试 aThunkDispatch<any, any, AnyAction>代替,这将起作用。


推荐阅读