【问题标题】:typescript react redux actions that return promises打字稿反应返回承诺的redux动作
【发布时间】:2020-05-11 01:08:34
【问题描述】:

在我的 react 应用程序中,我喜欢将 redux 实现从 View 逻辑中隐藏在它自己的包“我称之为 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 underhood 提供动力。

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

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

绑定选择器

代码

// @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));
    },

}

这个我以前基本上是直接调用选择器对象,因为第一个参数总是存储。

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 类型..

绑定调度

它的工作原理很像 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 errorProperty 'catch' 在类型'(dispatch: any, getState: any, { }: { }) => any'上不存在`

所以基本上因为 fetch 操作看起来像这样

const fetch = (params) =&gt; (dispatch) =&gt; api.get('/media', params); 所以它需要一个函数(dispatch),那么我如何告诉 typescript 跳过 thunk 并处理 thunk 函数的返回值

【问题讨论】:

    标签: javascript reactjs typescript redux


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2019-04-25
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      • 2018-01-08
      • 2020-04-06
      • 2016-11-14
      • 1970-01-01
      • 2018-01-21
      相关资源
      最近更新 更多