在我的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函数。
代码
// @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类型。
它的工作原理与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));
},
});
}
如果我派遣一个返回承诺的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函数的返回值
答案 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;
}
}