首页 > 解决方案 > TypeScript:删除索引签名而不隐式出现“任何”类型错误

问题描述

细节

我正在尝试创建一个辅助函数来组合我的减速器,以使全局减速器与反应的useReducer钩子和上下文 API 一起使用。我有它的功能,但我目前对类型检查不满意。

问题

为了让它工作,我必须添加Reducers 类型[key: string]: Reducer<any>[key: string]: any;GlobalState 类型。如果我删除它们,我会收到错误

元素隐含地具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型“全局状态”。在“GlobalState”类型上找不到具有“字符串”类型参数的索引签名。

元素隐含地具有“any”类型,因为“string”类型的表达式不能用于索引类型“Reducers”。在“Reducers”类型上找不到带有“字符串”类型参数的索引签名。

这给我留下了一个combineReducers功能,我可以将状态键命名为任何东西

一个例子

我有一个这样的初始状态:{page: {some state}, state2: {some state}} 然后我像这样组合减速器:combineReducers({ pages: pageReducer, state3: reducer2 });

我现在会有一个看起来像的状态,{page: {some state}, state2: {some state}}, pages: {some state}, state3: {some state}因为“意外地”错误地命名了状态键。

问题

[key: string]: Reducer<any>在 Reducers 类型和GlobalState 类型中删除时,有没有办法[key: string]: any;让它工作?

代码

类型.ts

export type GlobalReducer = (state: GlobalState, action: Action) => GlobalState;
export type Reducer<State> = (state: State, action: Action) => State;

export type Reducers = {
    [key: string]: Reducer<any>;
    page: Reducer<PageState>;
    state2: Reducer<AnotherState>;
};

export type GlobalState = {
    [key: string]: any;
    page: PageState;
    state2: AnotherState;
};

export type PageState = {
    title: string;
    loading: true;
};

export type AnotherState = {
    hello: string;
};

combineReducers.ts

import _ from "lodash";

import { Action, Reducers, GlobalState, GlobalReducer } from "./types";

const combineReducers = (reducers: Reducers): GlobalReducer => {
    return (state: GlobalState, action: Action): GlobalState => {
        const reducerKeys = Object.keys(reducers);

        reducerKeys.forEach((key) => {
            const newState = reducers[key](state[key], action);
            state = _.isEqual(newState, state[key]) ? state : { ...state, [key]: newState };
        });

        return state;
    };
};

export { combineReducers };

索引.ts

export const globalReducer = combineReducers({ page: pageReducer, state2: reducer2 });

初始状态.ts

export const initialState: GlobalState = {
    page: {
        title: "Holidaze",
        loading: true
    },
    state2: {
        hello: ""
    }
};

标签: typescript

解决方案


Object.keys返回一个字符串数组。您必须转换为keyof Reducers.

const reducerKeys = Object.keys(reducers) as (keyof Reducers)[];

type GlobalState = {
    page: State1,
    anotherPage: AnotherState,
}

type GlobalReducer<State> = (state: State, action: Action) => State;
type Reducer<State> = (state: State, action: Action) => State;

type Reducers<State> = { [K in keyof State]: Reducer<State[K]> }

const combineReducers = <State>(reducers: Reducers<State>): GlobalReducer<State> => {
    return (state: State, action: Action): State => {
        const reducerKeys = Object.keys(reducers) as (keyof State)[];

        reducerKeys.forEach((key) => {
            const newState = reducers[key](state[key], action);
            state = _.isEqual(newState, state[key]) ? state : { ...state, [key]: newState };
        });

        return state;
    };
};


推荐阅读