首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Redux + TypeScript和mapDispatchToProps

Redux + TypeScript和mapDispatchToProps
EN

Stack Overflow用户
提问于 2019-10-15 09:15:43
回答 3查看 1.3K关注 0票数 2

这应该很容易,但我现在还不明白,但我觉得这应该是一个简单的解决方案。我目前在typescript中使用redux,在异步操作创建器中使用redux-thunk

设置很简单。下面是我用来登录的代码:

代码语言:javascript
复制
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文件中调用它,以便导航到其他地方。

因此,当我在组件中执行类似操作时,它的工作方式与您期望的一样:

代码语言:javascript
复制
const { dispatch } = store;

dispatch(requestAuthenticationAsync('email', 'password')).then(() => {
    // navigate somewhere
});

但是,当我使用react-redux中的connectmapDispatchToProps时,如下所示:

代码语言:javascript
复制
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));

我得到以下错误:

代码语言:javascript
复制
TS2339: Property 'then' does not exist on type '(dispatch: ThunkDispatch<IState, undefined, IAction>) => Promise<void>'.

怎么回事?在这种情况下,我如何让TypeScript高兴,这样我才能在.then中使用promise

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-10-16 01:34:49

这实际上是一个我一定忽略了的非常简单的解决方案。特定道具的组件中的类型错误。

而不是:

代码语言:javascript
复制
requestAuthenticationAsync: typeof requestAuthenticationAsync;

我将其更改为:

代码语言:javascript
复制
requestAuthenticationAsync: ReturnType<requestAuthenticationAsync>;

这能够捕获(email: string, password: string) => Promise<void>类型,编译器停止了抱怨,一切都正常了。

票数 0
EN

Stack Overflow用户

发布于 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 todaywhat is in the repo相比,类型定义相对更多。

要使用这些(在新版本的redux-thunk或DefinitelyTyped中发布之前),您可以使用以下内容创建一个类型文件(例如:types.d.ts):

代码语言:javascript
复制
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来说并不是必须的,但我发现避免“双精度”类型会更容易一些):

代码语言:javascript
复制
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,以便在组件中使用。

代码语言:javascript
复制
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");
  });
};
票数 2
EN

Stack Overflow用户

发布于 2019-10-15 09:42:33

因为我不能写评论,所以我想检查一下我在这里理解和留下了什么。

如果您在代码的onGatewaySubmit函数中调用requestAuthenticationAsync,如下所示;

代码语言:javascript
复制
requestAuthenticationAsync(email, password).then(() => {
    console.log('done');
});

我感觉你是在像下面这样调用调度的函数

代码语言:javascript
复制
dispatch(requestAuthenticationAsync)(email, password).then(() => {
  // navigate somewhere
});

不是你所写的那样

代码语言:javascript
复制
dispatch(requestAuthenticationAsync('email', 'password')).then(() => {
  // navigate somewhere
});

这可能是离题的,但你能解释一下流程吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58385940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档