Действие назначается типом «никогда», когда оно точно не должно - PullRequest
0 голосов
/ 04 ноября 2018

Отказ от ответственности: я использую электронный шаблон от https://github.com/iRath96/electron-react-typescript-boilerplate

Там есть несколько хороших кодов создателей действий (скопируйте вставку из шаблона для лучшего контекста:)

import { Action } from 'redux'

export interface IAction extends Action {}
export interface IActionWithPayload<T> extends IAction {
  readonly payload: T
}

interface IActionCreator<T> {
  readonly type: string
  (payload: T): IActionWithPayload<T>

  test(action: IAction): action is IActionWithPayload<T>
}

interface IActionCreatorVoid {
  readonly type: string
  (): IAction

  test(action: IAction): action is IAction
}

export const actionCreator = <T>(type: string): IActionCreator<T> =>
  Object.assign((payload: T): IActionWithPayload<T> => ({ type, payload }), {
    type,
    test(action: IAction): action is IActionWithPayload<T> {
      return action.type === type
    },
  })

export const actionCreatorVoid = (type: string): IActionCreatorVoid =>
  Object.assign((): IAction => ({ type }), {
    type,
    test(action: IAction): action is IAction {
      return action.type === type
    },
  })

Итак, для создания новых действий я просто делаю:

export const fetchAllBackgroundsPending = actionCreatorVoid('FETCH_BACKGROUNDS_PENDING')
export const fetchAllBackgroundsSuccess = actionCreator<IBackground[]>('FETCH_BACKGROUNDS_SUCCESS')
export const fetchAllBackgroundsRejected = actionCreator<IAPIError>('FETCH_BACKGROUNDS_REJECTED')

И это работает просто отлично: мой action.payload теперь набран.

Однако, если я использую более 2 веток в моем редукторе, я получаю тип «никогда» в моей полезной нагрузке:

const backgroundsReducer = (
  state: IBackgroundsState = initialState,
  action: IAction
): IBackgroundsState => {
  if (fetchAllBackgroundsPending.test(action)) {
    return {
      ...state,
      isCollectionLoading: true,
    }
  }

  if (fetchAllBackgroundsSuccess.test(action)) {
    return {
      ...state,
      // action has a type of never!
      byId: mergeById(state, action.payload)
    }
  }

  return state
}

Насколько я могу судить по документам, TS намекает мне, что ветвь кода никогда не запустится, но это не так: если я поставлю console.log, я могу наблюдать за ними! Итак, похоже, что TS совершает ошибку ... или я?

Я понимаю, что приведенный здесь код не похож на минимальный пример, поэтому, если он недостаточно ясен, пожалуйста, дайте мне знать, и я постараюсь найти минимальный репозиторий, иллюстрирующий эту проблему. Любая помощь приветствуется!

1 Ответ

0 голосов
/ 04 ноября 2018

fetchAllBackgroundsPending.test объявлен как определяемый пользователем тип защиты :

test(action: IAction): action is IAction

То есть вы говорите TypeScript, что предполагается, что test возвращает true тогда и только тогда, когда аргумент имеет тип IAction. Поскольку параметр action для backgroundsReducer имеет тип IAction, если fetchAllBackgroundsPending.test(action) возвращает false (указывая, что action не является IAction), то для action не осталось никакого возможного типа, поэтому это получает тип never.

Полагаю, что вы действительно хотите test - это односторонний тип защиты, который TypeScript еще не поддерживает . Но в этом случае было бы хорошо просто изменить тип возвращаемого значения test в IActionCreatorVoid на обычный boolean (в результате чего test больше не будет определяемым пользователем типом защиты вообще), так как "true "Дело не определяло более конкретный тип действия в любом случае. Я бы посоветовал вам подать жалобу на шаблонный проект, который вы использовали.

Хотя метод test для IActionCreator в принципе также должен быть односторонним, текущее объявление вряд ли вызовет проблемы, потому что когда вы тестируете переменную типа IAction, случай «ложь» просто оставляет переменную как IAction; В TypeScript в настоящее время нет способа выразить исключение IActionWithPayload<T> из IAction.

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