reactjs - thunk 调度的 TypeScript 类型是否正确?

标签 reactjs typescript redux redux-thunk

我有一个异步 redux 操作,因此正在使用 thunk 中间件。

我有mapStateToProps , mapDispatchToPropsconnect组件的功能如下:

const mapStateToProps = (store: IApplicationState) => {
  return {
    loading: store.products.loading,
    products: store.products.products
  };
};
const mapDispatchToProps = (dispatch: any) => {
  return {
    getAllProducts: () => dispatch(getAllProducts())
  };
};
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ProductsPage);

这一切都有效,但我想知道是否可以替换 anymapDispatchToProps 中输入调度参数?

我试过ThunkDispatch<IApplicationState, void, Action>但在 connect 函数上出现以下 TypeScript 错误:

Argument of type 'typeof ProductsPage' is not assignable to parameter of type 'ComponentType<Matching<{ loading: boolean; products: IProduct[]; } & { getAllProducts: () => Promise<void>; }, IProps>>'.
  Type 'typeof ProductsPage' is not assignable to type 'ComponentClass<Matching<{ loading: boolean; products: IProduct[]; } & { getAllProducts: () => Promise<void>; }, IProps>, any>'.
    Types of property 'getDerivedStateFromProps' are incompatible.
      Type '(props: IProps, state: IState) => { products: IProduct[]; search: string; }' is not assignable to type 'GetDerivedStateFromProps<Matching<{ loading: boolean; products: IProduct[]; } & { getAllProducts: () => Promise<void>; }, IProps>, any>'.
        Types of parameters 'props' and 'nextProps' are incompatible.
          Type 'Readonly<Matching<{ loading: boolean; products: IProduct[]; } & { getAllProducts: () => Promise<void>; }, IProps>>' is not assignable to type 'IProps'.
            Types of property 'getAllProducts' are incompatible.
              Type '() => Promise<void>' is not assignable to type '() => (dispatch: Dispatch<AnyAction>) => Promise<void>'.
                Type 'Promise<void>' is not assignable to type '(dispatch: Dispatch<AnyAction>) => Promise<void>'.
                  Type 'Promise<void>' provides no match for the signature '(dispatch: Dispatch<AnyAction>): Promise<void>'.

enter image description here

是否可以替换 anymapDispatchToProps 中输入调度参数?

最佳答案

这个设置对我来说非常有效:

// store.ts
//...
export type TAppState = ReturnType<typeof rootReducer>;
export type TDispatch = ThunkDispatch<TAppState, void, AnyAction>;
export type TStore = Store<TAppState, AnyAction> & { dispatch: TDispatch };
export type TGetState = () => TAppState;
//...
const store: TStore = createStore(
  rootReducer,
  composeEnhancers(applyMiddleware(...middleware), ...enhancers)
);
export default store;

我的设置中的 rootReducer 看起来像这样 const rootReducer = createRootReducer(history);

// createRootReducer.ts
import { combineReducers, Reducer, AnyAction } from 'redux';
import { History } from 'history';
import {
  connectRouter,
  RouterState,
  LocationChangeAction,
} from 'connected-react-router';
// ... here imports of reducers
type TAction = AnyAction & LocationChangeAction<any>;

export type TRootReducer = Reducer<
  {
    // ... here types of the reducer data slices
    router: RouterState;
  },
  TAction
>;
const createRootReducer = (history: History): TRootReducer =>
  combineReducers({
    // ... here actual inserting imported reducers
    router: connectRouter(history),
  });

export default createRootReducer;

然后在连接的组件中

import { connect } from 'react-redux';
import Add, { IProps } from './Add'; // Component
import { TDispatch, TAppState } from '../../store';

type TStateProps = Pick<
  IProps,
  'title' | 'data' | 'loading'
>;
const mapStateToProps = (
  state: TAppState,
): TStateProps => {
    // ... here you have typed state :)
    // and return the TStateProps object as required
    return {
      loading: state.someReducer.loading,
      //...
    }
}

type TDispatchProps = Pick<IProps,  'onSave'>;
const mapDispatchToProps = (
  dispatch: TDispatch,
): TDispatchProps => {
   // here you  have typed dispatch now
   // return the TDispatchProps object as required
   return {
    onSave: (): void => {
      dispatch(saveEntry()).then(() => {
        backButton();
      });
    },
   }
}

至于thunk Action 我做如下

// this is a return type of the thunk
type TPromise = Promise<ISaveTaskResponse | Error>;

export const saveEntry = (): ThunkAction<
  TPromise, // thunk return type
  TAppState, // state type
  any, // extra argument, (not used)
  ISaveEntryAction // action type
> => (dispatch: TDispatch, getState: TGetState): TPromise => {
  // use getState
  // dispatch start saveEntry action
  // make async call
  return Axios.post('/some/endpoint', {}, {})
    .then((results: { data: ISaveTaskResponse; }): Promise<ISaveTaskResponse> => {
      // get results
      // you can dispatch finish saveEntry action
      return Promise.resolve(data);
    })
    .catch((error: Error): Promise<Error> => {
      // you can dispatch an error saveEntry action
      return Promise.reject(error);
    });
};

关于reactjs - thunk 调度的 TypeScript 类型是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52977666/

相关文章:

Facebook 社交插件评论部分被类名 Conceal (ReactJS)

javascript - Jest spyOn 不是函数

reactjs - 如何使用 Reactjs 组件渲染存储在数据库中的 HTML 和代码 - 未格式化渲染

typescript - 从 TypeScript 中的基本类型创建唯一类型?

typescript - Angular 2 + Ionic 2 + Barcode Scanner DOM 不更新绑定(bind)更改

seo - 将 prerender.io 与 ReactJS 一起用于 SEO

typescript - 使用 react-native-typescript-transformer 编译 TypeScript?

javascript - 使用 redux 工具包时出现错误 "A non-serializable value was detected in the state"- 但不是普通的 redux

reactjs - 对于 Redux 存储来说多大才算太大?

javascript - Redux saga,如何从组件中监听一个 Action