TypeScript: при удалении подписи индекса без явного получения возникает ошибка типа any - PullRequest
0 голосов
/ 27 апреля 2020

Подробности

Я пытаюсь создать вспомогательную функцию, чтобы объединить мои редукторы, чтобы иметь глобальный редуктор для использования с useReducer ловушкой реагирования и контекстным API. У меня есть работающая функциональность, но в настоящее время я не доволен проверкой типов.

Проблема

Чтобы она работала, мне пришлось добавить [key: string]: Reducer<any> в тип Редукторы и [key: string]: any; в типе GlobalState. Если я их удаляю, я получаю ошибки

Элемент неявно имеет тип 'any', потому что выражение типа 'string' нельзя использовать для индексации типа 'GlobalState'. Для типа «GlobalState» не найдено сигнатуры индекса с параметром типа «строка».

Элемент неявно имеет тип «любой», поскольку выражение типа «строка» нельзя использовать для индексации типа «Редукторы» ». Нет подписи индекса с параметром типа 'string' для типа '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> в тип Редукторы и [key: string]: any; в типе GlobalState?

Код

types.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;
};

combReducers.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 };

index.ts

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

initialState.ts

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

1 Ответ

1 голос
/ 27 апреля 2020

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;
    };
};

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...