web-dev-qa-db-ja.com

サンクディスパッチのTypeScriptタイプは正しいですか?

非同期のreduxアクションがあるので、サンクミドルウェアを使用しています。

次のように、コンポーネントにmapStateToPropsmapDispatchToProps、およびconnect関数があります。

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);

これはすべて機能しますが、anyのディスパッチパラメータのmapDispatchToPropsタイプを置き換えることができるかどうか疑問に思いましたか?

私は試した ThunkDispatch<IApplicationState, void, Action>しかし、接続関数で次の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

anyのディスパッチパラメータのmapDispatchToPropsタイプを置き換えることは可能ですか?

14
Carl Rippon

Reduxはプレーンオブジェクトであるアクションをディスパッチできます。そのようなアクションがあるとしましょう_{type: 'ACTION2'}_。アクションクリエーターを作成して、このようにディスパッチ内にラップすることができます

_// This is our action
interface Action2 extends Action { type: "ACTION2"; }

// And this is action crator
const action2 = (): Action2 => ({ type: "ACTION2" });
_

thunkミドルウェアを使用すると、Reduxは関数をディスパッチできます。そして、このような非同期アクションを作成できます

_// This action will be dispatched from async action creator
interface Action1 extends Action { type: "ACTION1"; payload: string; }

// And async action creator
const thunkAction = (arg: string): ThunkAction<Promise<void>, {}, AppState, KnownActions> => 
    async dispatch => {
        const res = await asyncFunction(arg);
        dispatch({ type: "ACTION1", payload: res });
    },  
_

ここでは_ThunkAction<R, S, E, A extends Action>_タイプが使用されます。次の型引数を受け入れます。

  • Rは、内部関数の戻り値の型を表します。上記の例では、内部関数は非同期関数であるため、_Promise<void>_を返します。
  • Sはアプリの状態のままです
  • Eは、使用されない拡張属性タイプです。
  • Aはアクションのタイプです。上記の例のKnownActionsは、考えられるすべてのアクションタイプの和集合です(_type KnownActions = Action1 | Action2;_)

次に、コンポーネントを入力する方法を見てみましょう。

_interface Component1DispatchProps {
  action2: () => Action2;
  thunkAction: (arg: string) => Promise<void>;
}

interface Component1StateProps {
  stateprop: string;
}

const mapDispatchToProps = (
  dispatch: ThunkDispatch<AppState, {}, KnownActions>
) => {
  return {
    action2: () => dispatch(action2()),
    thunkAction: (arg: string) => 
      dispatch(thunkAction(arg))
  };
};
_

thunkActionメソッドはdispatch(thunkAction(arg))を返します。ここで、thunkAction(arg)は_ThunkAction<Promise<void>, {}, AppState, KnownActions>_を返します。したがって、dispatchはタイプThunkActionの引数で呼び出され、次のように解決されます。

_<TReturnType>(
  thunkAction: ThunkAction<TReturnType, TState, TExtraThunkArg, TBasicAction>,
): TReturnType;
_

その結果、この例ではdispatch(thunkAction(arg))TReturnTypeまたは_Promise<void>_を返します。このような署名は、_Component1DispatchProps_のthunkActionに設定されます。

完全な例は ここ

0
Fyodor

グローバルタイプ定義でreduxDispatch関数に別のオーバーライドを提供することもできます。

(これをglobal.d.tsまたは他のグローバルタイプ定義内に配置します)

import { ThunkAction } from 'redux-thunk';
import { Action } from 'redux';

declare module 'redux' {
    export interface Dispatch<A extends Action = AnyAction> {
        <T extends ThunkAction<any, any, any, any>>(action: T): T extends ThunkAction<infer K, any, any, any> ? K : never;
    }
}

次に、mapDispatchToPropsで、ThunkDispatchではなくDispatchタイプを使用します。

0
Kaca992