Как избежать использования литеральных строк для сужения непересекающихся объединений в потоке

#redux #flowtype

#redux #flowtype

Вопрос:

Все примеры, которые я нахожу в Интернете для сужения непересекающегося объединения в flowtype, используют строковые литералы, подобные официальному. Я хотел бы знать, есть ли способ проверить значение из перечисления, например:

 const ACTION_A = 'LITERAL_STRING_A';
const ACTION_B = 'LITERAL_STRING_B';

type ActionA = {
  // This is not allowed
  type: ACTION_A,
  // type: 'LITERAL_STRING_A' is allowed
  dataA: ActionAData,
}

type ActionB = {
  // This is not allowed
  type: ACTION_B,
  // type: 'LITERAL_STRING_B' is allowed
  dataB: ActionBData,
}

type Action = ActionA | ActionB;

function reducer(state: State, action: Action): State {
  // Want to narrow Action to ActionA or ActionB based on type
  switch (action.type) {
    // case 'LITERAL_STRING_A': -- successfully narrow the type
    case ACTION_A: // doesn't work
      // action.dataA is accessible
      ...
  }
  ...
}
 

К сожалению, вы не можете этого сделать, потому что строки недопустимы в качестве аннотаций типов.

Если есть какой-либо другой способ обойти это, который не заставляет вводить строковые литералы везде, я хотел бы знать.

Если нет способа обойти это, также примите предложения на более высоком уровне о том, как не нужно определять эти непересекающиеся наборы для действий redux.

Ответ №1:

Я сейчас не в лучшей форме, поэтому извините, если я неправильно прочитал ваш вопрос. Я все равно постараюсь помочь. Это то, что вы ищете?

 const actionTypes = {
  FOO: 'FOO',
  BAR: 'BAR'
}

type ActionType = $Keys<actionTypes> // one of FOO, BAR

function buzz(actionType: ActionType) {
  switch(actionType) {
    case actionTypes.FOO:
      // blah
  }
 

Это должно сработать. Извините, если мой синтаксис немного не в порядке.

Если вы спрашиваете, как избежать перечисления всех типов действий type Action = ActionA | ActionB , тогда извините, я не знаю, я думаю, что это так, как вы это делаете. Если я правильно помню, недавно в Flow был введен немного более приятный синтаксис для определения длинных объединений:

 type Action =
  | ActionA
  | ActionB
  | ActionC
 

Кроме того, если вам не нужны отдельные типы действий, вы можете просто сделать

 type Action =
  | {type: ACTION_A; dataA: ActionAData;}
  | {type: ACTION_B; dataB: ActionBData;}
 

Комментарии:

1. Я спрашивал об сужении типа действия до типа ActionA или ActionB. Таким образом, я мог бы получить доступ к полям каждого подтипа без жалоб потока. Я вижу, что это делается с литеральными строками в примерах, но хотел бы знать, возможно ли это с перечислениями

2. @xvaldetaro А, понятно, спасибо за обновление вопроса. Это странно. Казалось бы, уточнение константами должно работать так же, как уточнение строковыми литералами. Может type: typeof ACTION_A быть, определение действия сработает?

Ответ №2:

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

Попробуйте flow…

 const ACTION_A:'LITERAL_STRING_A' = 'LITERAL_STRING_A';
const ACTION_B:'LITERAL_STRING_B' = 'LITERAL_STRING_B';
 

пример потока