这应该很容易,但我现在还不明白,但我觉得这应该是一个简单的解决方案。我目前在typescript中使用redux,在异步操作创建器中使用redux-thunk。
设置很简单。下面是我用来登录的代码:
export function requestAuthenticationAsync(email: string, password: string) {
return (dispatch: ThunkDispatch<IState, undefined, IAction>): Promise<void> => {
dispatch(requestAuthentication());
return postAuthentication(email, password).then((response) => {
dispatch(receiveAuthentication());
return response.json();
}).then((data) => {
dispatch(receiveUser(data));
});
};
}理想的情况是,当登录成功时,我可以使用.then在.tsx文件中调用它,以便导航到其他地方。
因此,当我在组件中执行类似操作时,它的工作方式与您期望的一样:
const { dispatch } = store;
dispatch(requestAuthenticationAsync('email', 'password')).then(() => {
// navigate somewhere
});但是,当我使用react-redux中的connect和mapDispatchToProps时,如下所示:
import './Gateway.scss';
import * as React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { requestAuthenticationAsync } from './actions';
import { withRouter } from 'react-router-dom';
const mapDispatchToProps = (dispatch) => {
return {
requestAuthenticationAsync: bindActionCreators(requestAuthenicationAsync, dispatch)
};
};
const mapStateToProps = (state) => {
return {
authenticated: state.authentication.authenticated
};
};
class Gateway extends React.Component<{
authenticated: boolean;
requestAuthenticationAsync: typeof requestAuthenticationAsync;
}, {
email: string;
password: string;
}> {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
onGatewaySubmit = (event) => {
event.preventDefault();
const { requestAuthenticationAsync } = this.props;
const { email, password } = this.state;
requestAuthenticationAsync(email, password).then(() => {
console.log('done');
});
};
onEmailValueChange = (event) => {
this.setState({
email: event.target.value
});
};
onPasswordValueChange = (event) => {
this.setState({
password: event.target.value
});
};
render() {
return (
<div id='gateway'>
<form onSubmit={ this.onGatewaySubmit }>
<input
className='email'
onChange={ this.onEmailValueChange }
placeholder='email'
type='text' />
<input
className='password'
onChange={ this.onPasswordValueChange }
placeholder='password'
type='password' />
<input type='submit' value='Submit' />
</form>
</div>
);
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Gateway));我得到以下错误:
TS2339: Property 'then' does not exist on type '(dispatch: ThunkDispatch<IState, undefined, IAction>) => Promise<void>'.怎么回事?在这种情况下,我如何让TypeScript高兴,这样我才能在.then中使用promise
发布于 2019-10-16 01:34:49
这实际上是一个我一定忽略了的非常简单的解决方案。特定道具的组件中的类型错误。
而不是:
requestAuthenticationAsync: typeof requestAuthenticationAsync;我将其更改为:
requestAuthenticationAsync: ReturnType<requestAuthenticationAsync>;这能够捕获(email: string, password: string) => Promise<void>类型,编译器停止了抱怨,一切都正常了。
发布于 2019-10-15 10:20:59
问题的根本原因是redux-thunk是由redux执行的中间件,所以它会调用函数(thunk)并返回值。然而,TypeScript并不“意识到”这种情况的发生,所以没有办法正确地键入它(如果没有一点额外的工作)。
redux-thunk包(此时)实际上附带了类型定义。然而,它的类型定义已经有了许多重大的改进,但没有发布。在3.0版本的It sounds like中,它们将被移除并移动到DefinitelyTyped (可通过@types/redux-thunk安装)。
但在此之前,您可以自己设置类型。如果compare what is released today与what is in the repo相比,类型定义相对更多。
要使用这些(在新版本的redux-thunk或DefinitelyTyped中发布之前),您可以使用以下内容创建一个类型文件(例如:types.d.ts):
import { ActionCreatorsMapObject } from "redux";
import { ThunkAction } from "redux-thunk";
/**
* Redux behaviour changed by middleware, so overloads here
*/
declare module "redux" {
/**
* Overload for bindActionCreators redux function, returns expects responses
* from thunk actions
*/
function bindActionCreators<
TActionCreators extends ActionCreatorsMapObject<any>
>(
actionCreators: TActionCreators,
dispatch: Dispatch
): {
[TActionCreatorName in keyof TActionCreators]: ReturnType<
TActionCreators[TActionCreatorName]
> extends ThunkAction<any, any, any, any>
? (
...args: Parameters<TActionCreators[TActionCreatorName]>
) => ReturnType<ReturnType<TActionCreators[TActionCreatorName]>>
: TActionCreators[TActionCreatorName]
};
}这是直接从今天的回购中提取的。如果您需要更多,您可以复制整个文件,但这一部分应该可以解决您的问题。
然后,更新您对bindActionCreators的调用,以传递一个对象并推断出这些类型(这对于mapStateToProps来说并不是必须的,但我发现避免“双精度”类型会更容易一些):
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
const mapDispatchToProps = dispatch => {
return bindActionCreators({ requestAuthenticationAsync }, dispatch);
};
type StateProps = ReturnType<typeof mapStateToProps>;
const mapStateToProps = state => ({
authenticated: state
});
type Props = DispatchProps & StateProps;
class Gateway extends React.Component<Props> {
// ...
}类型可以更新,但是对于redux-thunk代码库中的类型,他们希望bindActionCreators的第一个参数是一个对象(尽管是the docs say it can be either a function as you were using or an object),这是通过查看TActionCreators extends ActionCreatorsMapObject<any>来实现的。
现在应该可以正确地键入this.props.requestAuthenticationAsync,以便在组件中使用。
onGatewaySubmit = event => {
event.preventDefault();
const { requestAuthenticationAsync } = this.props;
const { email, password } = this.state;
// Type:
// (email: string, password: string) => Promise<void>
requestAuthenticationAsync(email, password).then(() => {
console.log("done");
});
};发布于 2019-10-15 09:42:33
因为我不能写评论,所以我想检查一下我在这里理解和留下了什么。
如果您在代码的onGatewaySubmit函数中调用requestAuthenticationAsync,如下所示;
requestAuthenticationAsync(email, password).then(() => {
console.log('done');
});我感觉你是在像下面这样调用调度的函数
dispatch(requestAuthenticationAsync)(email, password).then(() => {
// navigate somewhere
});不是你所写的那样
dispatch(requestAuthenticationAsync('email', 'password')).then(() => {
// navigate somewhere
});这可能是离题的,但你能解释一下流程吗?
https://stackoverflow.com/questions/58385940
复制相似问题