在我的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属性'catch'在类型'(dispatch:any,getState:any,{}:{})=> any'上不存在

所以基本上因为提取动作看起来像这样

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

最佳答案

您可以在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;
    }
}

10-06 06:23