打字稿响应返回承诺的redux操作

时间:2020-01-24 17:11:23

标签: javascript reactjs typescript redux

在我的react应用程序中,我想将View逻辑中的redux实现隐藏在其自己的包“我称为sdk包”中,然后从sdk包中导出react的Hooks集,以便任何客户端都可以使用它。

简短的问题。

const fetch = (params) => (dispatch) => api.get('/media', params); 我怎样才能告诉打字稿跳过thunk并处理thunk函数的返回值 我有一个Record对象,如何键入它以跳过中间函数?

上下文

代码:

// hook.tsx
import * as actions from './actions'; // thunks
import * as selectors from './selectors'; // reselect.
import {useSelector, useDispatch} from 'react-redux';

export function useMedia(): [Selectors<typeof selectors>,Actions<typeof actions>] {
  // use ref to cache hook
  return  useRef([
    bindSelectors(selectors, useSelector),
    bindDispatch(actions, useDispatch()),
  ]).current;
}

现在在我的视图中,每当我需要使用我要使用的媒体片时。

import { useMedia } from '@sdk/media'

// ....
const [media, mediaActions] = useMedia();
// dispatch an action
mediaActions.fetch({limit:10}).then(console.log);
// select a slice using selector
const photos = media.photosOfAlbum(1);

我的视图不知道/不在乎useMedia的工作方式,因此我可以在代码库中真正拆分职责,并简化代码共享,测试等工作。因为可以随时切换实现而不会影响sdk(移动/ webapp /甚至nodejs)的使用者应用程序),没人知道redux为sdk底层提供了动力。

问题是我无法正确键入这些挂钩..(useMedia)。

所以我们在这里输入2件事。 bindSelectors函数和bindDispatch函数。

bindSelectors

代码

// @sdk/utils

function bindSelectors <T extends object>(selectors:T, useSelector): CurriedFunctionObject<T>{
  return new Proxy(selectors, {
    get: (main: T, key: keyof T, ctx: any) => {
      const fn = Reflect.get(main, key, ctx);

      // always inject store as first prop of fn
      // we get store arg from useSelector higher order (its already properly typed)
      return (props?: any) => useSelector(store => fn(store, props));
    },

}

这个我以前用来破解直接对选择器对象的调用,好像总是存储第一个arg一样。

export type CurriedFunctionObject<T> = {
  [P in keyof T]: T[P] extends (
    s: import('../rootReducer').AppState,
    ...p: infer Ps
  ) => infer R
    ? (...p: Ps) => R
    : never;
};

现在我的选择器已绑定并键入,我的主要问题是如何编写Actions类型。

bindDispatch

它的工作原理与bindSelectors类似。我使用“ redux-thunk”中的ActionCreatorsMapObject进行输入

export function bindDispatch<T extends Record<string, any>>(
  obj: T,
  dispatch: Dispatch,
): ActionCreatorsMapObject<T> {
  return new Proxy(obj, {
    get: (main: T, key: keyof T, ctx) => {
      const fn = Reflect.get(main, key, ctx);

      return (...props: any[]) => dispatch(fn(...props));
    },
  });
}

bindDispatch问题:-

如果我派遣一个返回承诺的thunk,则其输入类型不正确。

上面的代码media.fetch({limit:10}).then///.then is will give error的示例在类型'((dispatch:any,getState:any,{}:{})=> any'`中不存在属性'catch'

所以基本上,因为获取操作看起来像这样

const fetch = (params) => (dispatch) => api.get('/media', params);所以它期望一个函数(dispatch),所以我如何告诉打字稿跳过thunk并处理thunk函数的返回值

1 个答案:

答案 0 :(得分:0)

您可以在global.d.ts中定义类似的内容(或将其放在单独的redux.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;
    }
}