Redux减速器工厂类型问题中的Typescript映射类型
Posted
技术标签:
【中文标题】Redux减速器工厂类型问题中的Typescript映射类型【英文标题】:Typescirpt mapped typed in redux reducer factory typings problem 【发布时间】:2019-06-06 20:49:33 【问题描述】:我正在尝试实现类型安全的功能,以创建基于“动作处理程序”映射的减速器。我们的想法是让 API 看起来像这样:
export const Actions =
setToken: (token: string) => createAction(SET_TOKEN_TYPE, token),
invalidateToken: () => createAction(INVALIDATE_TOKEN_TYPE),
startLogin: () => createAction(START_LOGIN_TYPE)
;
export const reducer = createReducer<State, typeof Actions>(
[SET_TOKEN_TYPE]: ( loginError, ...state , action) => (
...state,
token: action.payload,
loading: false
),
[INVALIDATE_TOKEN_TYPE]: ( token, ...state ) => state,
[START_LOGIN_TYPE]: ( loginError, ...state ) => (
...state,
loading: true
)
,
loading: false
);
createReducer
函数应该(为了清楚起见没有 Typescript)看起来像这样:
function createReducer(handlers, initialState)
return (state = initialState, action) =>
if (action.type in handlers)
return handlers[action.type](state, action);
return state;
;
我创建了这样的类型化函数来保证类型安全:
interface Action<T extends string>
type: T;
type ActionCreator<T extends string> = (...args: any) => Action<T>;
type ActionsCreators =
[creator: string]: ActionCreator<any>;
;
type ActionsUnion<Actions extends ActionsCreators> = ReturnType<
Actions[keyof Actions]
>;
type ActionHandlers<ActionCreators extends ActionsCreators, State> =
[K in ReturnType<ActionCreators[keyof ActionCreators]>["type"]]: (
state: State,
action: ReturnType<ActionCreators[K]>
) => State
;
function createReducer<State, Actions extends ActionsCreators>(
handlers: ActionHandlers<Actions, State>,
initialState: State
)
return (
state: State = initialState,
action: ActionsUnion<Actions>
): State =>
if (action.type in handlers)
// unfortunately action.type is here any :(
return handlers[action.type](state, action); // here I have the error
return state;
;
在handlers[action.type]
我有错误(noImplicitAny: true
)
元素隐含地具有“any”类型,因为类型“ActionHandlers”没有索引签名。
知道如何在 reducer 中输入 action.type
吗?
你可以在the gist找到整个例子
【问题讨论】:
【参考方案1】:您收到错误的原因是 action.type
被隐式键入为 any
,因为没有应用适用的类型。
在链中的某个点,您使用 any
作为类型参数,用于需要植根于 string
的内容:
type ActionsCreators =
[creator: string]: ActionCreator<any>;
;
如果在这里添加类型参数可以替换any
;但是,您需要一直传递下去。
请参阅以下已进行此更新的版本。我不得不将一些中间类型重命名为通用名称(T
或 P
),因为我很难保持正确的类型。
有了额外的类型参数<P>
,我们现在有了一个用于以下而不是隐式any
的类型:
const f = handlers[action.type];
这里,f
变为 ActionHandlers<P, T, State>[P]
export interface Action<T extends string>
type: T;
export interface ActionWithPayload<T extends string, P> extends Action<T>
payload: P;
export type ActionCreator<T extends string> = (...args: any) => Action<T>;
export type ActionsCreators<T extends string> =
[creator: string]: ActionCreator<T>;
;
export type ActionsUnion<P extends string, T extends ActionsCreators<P>> = ReturnType<T[keyof T]>;
export type ActionHandlers<P extends string, T extends ActionsCreators<P>, State> =
[K in ReturnType<T[keyof T]>["type"]]: (
state: State,
action: ReturnType<T[K]>
) => State
;
export function createReducer<P extends string, State, T extends ActionsCreators<P>>(
handlers: ActionHandlers<P, T, State>,
initialState: State
)
return (state: State = initialState, action: ActionsUnion<P, T>): State =>
if (action.type in handlers)
const f = handlers[action.type];
return f(state, action);
return state;
;
【讨论】:
以上是关于Redux减速器工厂类型问题中的Typescript映射类型的主要内容,如果未能解决你的问题,请参考以下文章
使用 Redux 如何阻止 reducer 中的 switch 增长?
Springboot + mybatis + React+redux+React-router+antd+Typescript: React+Typescrip项目的搭建