Печатать редуктор высшего порядка; Типы параметров «состояние» и «состояние» несовместимы - PullRequest
0 голосов
/ 11 января 2020

Я пытаюсь набрать редуктор более высокого порядка, и мне удалось сузить проблему, проблема заключается в state введите redux определение типа Reducer, что S | undefined , Если я удаляю undefined и просто набираю state как S все работает как положено

export type Reducer<S = any, A extends Action = AnyAction> = (
  state: S | undefined,
  action: A
) => S

Проблема в том, что редуктор более высокого порядка не инициализирует состояние со значением по умолчанию, которое требуется redux, так как оно отправляет действие, которое не соответствует ни в одном редукторе, для заполнения хранилища начальным значением, но я предполагаю, что машинопись не может сказать, что внутренний редуктор справится с этим.

Какие у меня варианты здесь кроме удаления undefined из определения типа?

Тип mov ie в src > reducers.ts > RootState внизу never

Песочница

Редуктор высшего порядка

import { Action } from "redux";

const startReducer = <S>(state: S): S => ({
  ...state,
  loading: true,
  error: false
});

const successReducer = <S>(state: S): S => ({
  ...state,
  loading: false
});

const errorReducer = <S>(state: S): S => ({
  ...state,
  error: true,
  loading: false
});

type LoadingActionTypes = Record<"start" | "success" | "error", string>;

const withLoadingStates = ({ start, success, error }: LoadingActionTypes) => {
  const actionReducerMapper = {
    [start]: startReducer,
    [success]: successReducer,
    [error]: errorReducer
  };

  return <S, A extends Action>(baseReducer: (state: S, action: A) => S) => (
    state: S,
    action: A
  ): S => {
    const nextState = actionReducerMapper[action.type]
      ? actionReducerMapper[action.type](state)
      : state;

    return baseReducer(nextState, action);
  };
};

export default withLoadingStates;

Внутренний редуктор

import { combineReducers } from "redux";
import withLoadingStates from "./withLoadingStates";

const FETCH_MOVIE_BY_ID_START = "FETCH_MOVIE_BY_ID_START";
const FETCH_MOVIE_BY_ID_SUCCESS = "FETCH_MOVIE_BY_ID_SUCCESS";
const FETCH_MOVIE_BY_ID_ERROR = "FETCH_MOVIE_BY_ID_ERROR";

type FetchMovieByIdStartAction = { type: typeof FETCH_MOVIE_BY_ID_START };
type FetchMovieByIdSuccessAction = { type: typeof FETCH_MOVIE_BY_ID_SUCCESS };
type FetchMovieByIdErrorAction = { type: typeof FETCH_MOVIE_BY_ID_ERROR };

type MovieByIdActionTypes =
  | FetchMovieByIdStartAction
  | FetchMovieByIdSuccessAction
  | FetchMovieByIdErrorAction;

type LoadingStates = {
  loading: boolean;
  error: boolean;
};

const initialState: LoadingStates = {
  loading: false,
  error: false
};

const movieReducer = (state = initialState, action: MovieByIdActionTypes) =>
  state;

const wrappedReducer = withLoadingStates({
  start: FETCH_MOVIE_BY_ID_START,
  success: FETCH_MOVIE_BY_ID_SUCCESS,
  error: FETCH_MOVIE_BY_ID_ERROR
})(movieReducer);

export const rootReducer = combineReducers({
  movie: wrappedReducer
});

// movie type is never
export type RootState = ReturnType<typeof rootReducer>;

Ошибка, которую я получаю

(свойство) mov ie: Редуктор Без перегрузки соответствует этому вызову. Перегрузка 1 из 2, '(redurs: ReducersMapObject <{mov ie: LoadingStates; trending: Record;}, any>): Reducer <...>', вызвала следующую ошибку. Тип '(состояние: LoadingStates, action: MovieByIdActionTypes) => LoadingStates' нельзя назначить типу 'Reducer'. Типы параметров «состояние» и «состояние» несовместимы. Тип 'LoadingStates | undefined »нельзя назначить типу« LoadingStates ». Тип 'undefined' нельзя назначить типу 'LoadingStates'.ts (2769)

1 Ответ

1 голос
/ 11 января 2020

Вы можете изменить ваш withLoadingState редуктор высшего порядка следующим образом:

const withLoadingStates = ({ start, success, error }: LoadingActionTypes) => {
  const actionReducerMapper = {
    [start]: startReducer,
    [success]: successReducer,
    [error]: errorReducer
  };

  return <S, A extends Action>(
    baseReducer: (state: S | undefined, action: A) => S
  ) => (state: S | undefined, action: A): S => {
    const nextState = actionReducerMapper[action.type]
      ? actionReducerMapper[action.type](state)
      : state;

    return baseReducer(nextState, action);
  };
};

Затем типы принудительно возвращают свернутый редуктор, который принимает undefined для инициализации, а также требует, чтобы baseReducer возвращает состояние, когда оно вызывается со значением undefined. Вот модифицированная песочница: https://codesandbox.io/s/bold-visvesvaraya-15f5o

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