【问题标题】:Typescirpt mapped typed in redux reducer factory typings problemRedux减速器工厂类型问题中的Typescript映射类型
【发布时间】: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找到整个例子

【问题讨论】:

    标签: typescript redux typescript-typings mapped-types


    【解决方案1】:

    您收到错误的原因是 action.type 被隐式键入为 any,因为没有应用适用的类型。

    在链中的某个点,您使用 any 作为类型参数,用于需要植根于 string 的内容:

    type ActionsCreators = {
        [creator: string]: ActionCreator<any>;
    };
    

    如果在这里添加类型参数可以替换any;但是,您需要一直传递下去。

    请参阅以下已进行此更新的版本。我不得不将一些中间类型重命名为通用名称(TP),因为我很难保持正确的类型。

    有了额外的类型参数&lt;P&gt;,我们现在有了一个用于以下而不是隐式any的类型:

    const f = handlers[action.type];
    

    这里,f 变为 ActionHandlers&lt;P, T, State&gt;[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;
        };
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      • 2018-02-05
      • 2013-12-31
      • 1970-01-01
      • 2017-08-08
      • 2019-03-21
      相关资源
      最近更新 更多