Typescript 显然为已派发的 Thunk 推断出错误的类型
Typescript apparently deduces the wrong type for a dispatched Thunk
完整的工作代码和框示例 here
我声明了一个简单的动作类型和一个调度它的异步 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)
但是,当我记录在运行时获得的值时(codesandbox 的第 48 行),我清楚地看到它是一个 Promise
。在 Whosebug 上搜索我发现了相互矛盾的答案。
says that dispatching a thunk returns the thunk itself. Whereas this answer 建议调度一个 thunk returns 一个 Promise。
Typescript 的类型系统似乎表明调度 thunk 的类型与 thunk 本身相同。但是在运行时我得到一个 Promise 对象。我错过了什么?
仅出于完整性目的,我附加了您将在沙箱中找到的代码(上面提供的link):
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);
thunk 的 return 值是 thunk 操作本身的 return 值。因此:如果它是一个异步函数,它 return 是一个 Promise。
正常的 Dispatch
类型不知道如何处理 thunk。
如果您使用的是 redux 工具包 this documentation part 描述了如何使用从商店配置推断出的 Dispatch 类型正确键入您的 useDispatch
挂钩。
如果你使用普通的 redux,你可以使用 ThunkDispatch
类型。 This part of the react-redux documentation 描述了在这种情况下如何键入 useDispatch
挂钩。
PS:在您的具体情况下,您的 ThunkDispatch<any, any, any>
太笼统了。最后一个 any
会过于急切地匹配。试试 ThunkDispatch<any, any, AnyAction>
,那会起作用。
完整的工作代码和框示例 here
我声明了一个简单的动作类型和一个调度它的异步 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)
但是,当我记录在运行时获得的值时(codesandbox 的第 48 行),我清楚地看到它是一个 Promise
。在 Whosebug 上搜索我发现了相互矛盾的答案。
Typescript 的类型系统似乎表明调度 thunk 的类型与 thunk 本身相同。但是在运行时我得到一个 Promise 对象。我错过了什么?
仅出于完整性目的,我附加了您将在沙箱中找到的代码(上面提供的link):
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);
thunk 的 return 值是 thunk 操作本身的 return 值。因此:如果它是一个异步函数,它 return 是一个 Promise。
正常的 Dispatch
类型不知道如何处理 thunk。
如果您使用的是 redux 工具包 this documentation part 描述了如何使用从商店配置推断出的 Dispatch 类型正确键入您的 useDispatch
挂钩。
如果你使用普通的 redux,你可以使用 ThunkDispatch
类型。 This part of the react-redux documentation 描述了在这种情况下如何键入 useDispatch
挂钩。
PS:在您的具体情况下,您的 ThunkDispatch<any, any, any>
太笼统了。最后一个 any
会过于急切地匹配。试试 ThunkDispatch<any, any, AnyAction>
,那会起作用。