React + Redux-Observable + Typescript - ошибка компиляции, аргумент не назначается - PullRequest
0 голосов
/ 21 ноября 2018

Я создаю приложение, используя React и Redux-Observable.Я новичок в этом, и я пытаюсь создать эпос для выполнения входа пользователя.

Мой эпос ниже:

export const loginUserEpic = (action$: ActionsObservable<Action>) =>
  action$.pipe(
    ofType<LoginAction>(LoginActionTypes.LOGIN_ACTION),
    switchMap((action: LoginAction) =>
      ajax({
        url,
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: { email: action.payload.username, password: action.payload.password },
      }).pipe(
        map((response: AjaxResponse) => loginSuccess(response.response.token)),
        catchError((error: Error) => of(loginFailed(error))),
      ),
    ),
  );

Проблема в том, что я получаю ошибку Typescript наэта строка: ofType<LoginAction>(LoginActionTypes.LOGIN_ACTION) говоря это:

Argument of type '(source: Observable<LoginAction>) => Observable<LoginAction>' is not assignable to parameter of type 'OperatorFunction<Action<any>, LoginAction>'.
  Types of parameters 'source' and 'source' are incompatible.
    Type 'Observable<Action<any>>' is not assignable to type 'Observable<LoginAction>'.
      Type 'Action<any>' is not assignable to type 'LoginAction'.
        Property 'payload' is missing in type 'Action<any>'.

Мои действия здесь:

export enum LoginActionTypes {
  LOGIN_ACTION = 'login',
  LOGIN_SUCCESS_ACTION = 'login-sucesss',
  LOGIN_FAILED_ACTION = 'login-failed',
}

export interface LoginAction extends Action {
  type: LoginActionTypes.LOGIN_ACTION;
  payload: {
    username: string;
    password: string;
  };
}

export function login(username: string, password: string): LoginAction {
  return {
    type: LoginActionTypes.LOGIN_ACTION,
    payload: { username, password },
  };
}

export interface LoginSuccessAction extends Action {
  type: LoginActionTypes.LOGIN_SUCCESS_ACTION;
  payload: {
    loginToken: string;
  };
}

export function loginSuccess(loginToken: string): LoginSuccessAction {
  return {
    type: LoginActionTypes.LOGIN_SUCCESS_ACTION,
    payload: { loginToken },
  };
}

export interface LoginFailedAction extends Action {
  type: LoginActionTypes.LOGIN_FAILED_ACTION;
  payload: {
    error: Error;
  };
}

export function loginFailed(error: Error): LoginFailedAction {
  return {
    type: LoginActionTypes.LOGIN_FAILED_ACTION,
    payload: { error },
  };
}

export type LoginActions = LoginAction | LoginSuccessAction | LoginFailedAction;

Как это исправить, не используя типы any на Epic?

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Вы можете оформить https://github.com/piotrwitek/react-redux-typescript-guide подробности здесь для всех стандартных способов использования React, Redux и Redux-Observable.

Я бы предложил использовать библиотеку typesafe-actions для достижениятипы.

Некоторые псевдокоды:

Действия

Вместо этого

export interface LoginSuccessAction extends Action {
  type: LoginActionTypes.LOGIN_SUCCESS_ACTION;
  payload: {
    loginToken: string;
  };
}

export function loginSuccess(loginToken: string): LoginSuccessAction {
  return {
    type: LoginActionTypes.LOGIN_SUCCESS_ACTION,
    payload: { loginToken },
  };
}

используйте typesafe-actions, безинтерфейс

actions/login/LoginActions.ts

import {action} from "typesafe-actions"

export function loginSuccess(loginToken: string) {
  return action(LoginActionTypes.LOGIN_SUCCESS_ACTION, { loginToken });
}

actions/login/LoginActionsModel.ts

import * LoginActions from "./LoginActions";
import { ActionCreator } from "typesafe-actions";

export type LoginActionCreator = ActionCreator<typeof LoginActions>

Затем экспортируйте все действия.

actions/index.ts

import { LoginActionCreator } from "./login/LoginActionModel";

export default type AllActions = LoginActionCreator

Epics

import { Epic } from "redux-observable";
import { isOfType } from "typesafe-actions";
import { filter } from "rxjs/operators";
export const loginUserEpic: Epic<AllActions> = (action$) =>
  action$.pipe(
    filter(isOfType((LoginActionTypes.LOGIN_ACTION))),
    switchMap((action: LoginAction) =>
      ajax({
        url,
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: { email: action.payload.username, password: action.payload.password },
      }).pipe(
        map((response: AjaxResponse) => loginSuccess(response.response.token)),
        catchError((error: Error) => of(loginFailed(error))),
      ),
    ),
  );

Если Epics взяты из библиотеки redux-observable, AllActions - это действия, которые являются вводом и выводом эпосов.

Типы следующие:

Epic<InputActions, OutputActions, Store>
Epic<Actions(Input&Output)>

В случае, если вы хотите использовать хранилище из RedEx, вам нужен RootState (из корневого редуктора)

export const someEpic: Epic<AllActions, AllActions, RootState> = (action$, store$) 
=> action$.pipe(
  filter(isOfType(SOMETYPE)),
  mergeMap(action => {
    const a = store$.value.a;
    return someActions(a, action.payload.b);
  })
0 голосов
/ 25 января 2019

Typescript выдает ошибку, потому что вы установили ActionsObservable действие, универсальное изложение Action, которое является интерфейсом с формой { type: string }.Таким образом, Typescript считает, что все поступающие действия будут иметь только тип, но вы устанавливаете для ofType оператора фильтрации другой тип действия, даже если он расширяет интерфейс действий с избыточностью. Typescript потребует bivarianceHack, чтобы позволить вам передавать все, что реализует этот интерфейс.,Один из самых простых обходных путей - изменить ActionsObservable<Action> на ActionsObservable<AnyAction>, с AnyAction, который импортируется из redux.

0 голосов
/ 20 января 2019

Оператор ofType, предлагаемый redux-observable, - не лучший способ различения типов объединений.Гораздо лучшим способом является использование функции isOfType, предоставляемой typesafe-actions.

import { filter } from 'rxjs/operators';
import { isOfType } from 'typesafe-actions';

Сначала давайте расскажем TypeScript о возможных действиях, используемых в вашем приложении.Ваш поток действий должен быть определен не как ActionsObservable<Action>, а как поток ваших действий: ActionsObservable<LoginActions>.

export const loginUserEpic = (action$: ActionsObservable<LoginActions>) =>

Теперь мы можем использовать предикат isOfType вместе соператор filter.Замените это:

ofType<LoginAction>(LoginActionTypes.LOGIN_ACTION)

следующим:

filter(isOfType(LoginActionTypes.LOGIN_ACTION))

Действие, переданное по потоку, будет правильно распознано как LoginAction.

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