非同期のreduxアクションがあるので、サンクミドルウェアを使用しています。
次のように、コンポーネントにmapStateToProps
、mapDispatchToProps
、および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>'.
any
のディスパッチパラメータのmapDispatchToProps
タイプを置き換えることは可能ですか?
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
に設定されます。
完全な例は ここ
グローバルタイプ定義で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タイプを使用します。