类型安全的使用与redux-thunk一起调度

时间:2020-01-18 13:10:11

标签: typescript redux redux-thunk

我正在使用redux-thunk来使用异步操作创建者。结果也将返回给相应的调用者。

function fetchUserName(userId: number): Promise<string> {
  return Promise.resolve(`User ${userId}`)
}

function requestUserName(userId: number) {
  return (dispatch: Dispatch) => {
    return fetchUserName(userId).then(name => {
      dispatch({
        type: 'SET_USERNAME',
        payload: name,
      })
    })
  }
}

这样,商店将得到更新,同时允许组件直接处理响应。

function User() {
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(requestUserName(1))
      .then(name => {
        console.log(`user name is ${name}`)
      })
      .catch(reason => {
        alert('failed fetching user name')
      })
  }, [])
}

这可以按预期工作,但是由于类型无效,TypeScript不会对其进行编译。

  1. dispatch返回的useDispatch未被识别为返回Promise的函数,因此TypeScript认为Property 'then' does not exist on type '(dispatch: Dispatch<AnyAction>) => Promise<void>'.
  2. 即使可以识别,也应该正确键入Promise

如何解决这种情况?

对于我来说,在useDispatch周围创建包装器或重新定义dispatch的类型对我来说是完全可以的,但是我不知道在这种特殊情况下该类型应该是什么样。

非常感谢您的任何建议。

2 个答案:

答案 0 :(得分:12)

useDispatch返回Dispatch类型used by Redux,因此您只能使用它调度标准操作。要还分派重击动作,请将其类型声明为ThunkDispatch(来自redux-thunk)。

ThunkDispatch接收存储状态extra thunk args和您的操作类型的类型参数。它允许调度ThunkAction,这基本上是requestUserName的内部功能。

例如,您可以这样输入:

import { ThunkDispatch } from "redux-thunk";
import { AnyAction } from "redux";

type State = { a: string }; // your state type
type AppDispatch = ThunkDispatch<State, any, AnyAction>; 
// or restrict to specific actions instead of AnyAction

function User() {
  const dispatch: AppDispatch = useDispatch();
  useEffect(() => {
    dispatch(requestUserName(1))
      .then(...)  // works now
  }, []);
  ...
}

AppDispatch也可以通过typeof store.dispatch从商店inferred>

import thunk, { ThunkDispatch, ThunkMiddleware } from "redux-thunk";

const mw: ThunkMiddleware<State, AnyAction> = thunk;
const dummyReducer = (s: State | undefined, a: AnyAction) => ({} as State);
const store = createStore(dummyReducer, applyMiddleware(mw));

type AppDispatch = typeof store.dispatch // <-- get the type from store

TS Playground sample

答案 1 :(得分:-4)

您应该用dispatch包裹Promise.resolve()

function User() {
  const dispatch = useDispatch()
  useEffect(() => {
    Promise.resolve(dispatch(requestUserName(1)))
      .then(name => {
        console.log(`user name is ${name}`)
      })
      .catch(reason => {
        alert('failed fetching user name')
      })
  }, [])
}