Как правильно фильтровать по значению перечисления в Typescript? - PullRequest
0 голосов
/ 21 октября 2018

Если у меня есть перечисление, определенное следующим образом:

export enum State {
    Archived = 0,
    OnShoppingListChecked = 1,
    OnShoppingListUnchecked = 2
}

и класс, использующий перечисление:

import { State } from "./State";
export class GroceryDto {
  public name: string = null;
  public currentState: State = null;
}
export default GroceryDto;

У меня есть некоторый код, который пытается фильтровать на основеcurrentState из GroceryDto, но не подходит для ввода в массив.

//...some code to fetch data
let activeGroceries = response.data.activeGroceries as GroceryDto[]; //casts correctly to an array of 4 items
let visibleGroceries = activeGroceries.filter(
  g => g.currentState === State.OnShoppingListUnchecked
);
//visibleGroceries is empty but should return the same 4 values

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

let filtered = visibleGroceries.filter(
  g =>
    g.currentState.toString() === State[State.OnShoppingListUnchecked]
);

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

Имейте в виду, что enum a в TypeScript вполне ... ну, они могут быть неправильно поняты и всегда могут использоваться как строковый и числовой тип.

Если вы используете enum в форме, подобной той, которую вы представили:

State.OnShoppingListUnchecked

Тогда она будет представлена ​​как число и сравнена с числовым значением 1. Но рассмотрим следующий перекрестный код перечисления:

a === State['OnShoppingListUnchecked'] // compare against 1
a === State[State['OnShoppingListUnchecked']] // compare against 'OnShoppingListUnchecked' string
a === State[State[State['OnShoppingListUnchecked']]] // Again against numeric 1
// ... and so one 

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

let toCompare = 1 // Field you wish to compare against
if(typeof(compareValue) === 'number') {
  return State[toCompare ] === compareValue // Compare number against number
} else if (typeof(compareValue) === 'string') {
  return State[State[toCompare ] === compareValue // compare input string against string representation of enum
}

Чтобы убедиться, что независимо от того, является ли введенная строка или число, вы всегда будете сравнивать с правильной enum записью.

И имейте в виду, что строковые перечисления поддерживаются начиная с TyeScript 2.4 и выше, и, по моему личному мнению, их использование должно быть сведено к минимуму, главным образом потому, что основанные на числах перечисления являются удобным способом выбора некоторой дополнительной информации из структур, упорядоченных по массивам.в то время как на основе строк невозможно использовать этот способ:

enum NamesEnum {
    NAME0 = 0,
    NAME1 = 1
};

namesToDisplay: string[] = [
  'Name1 display value',
  'Name2 display value'
];

let enumVal = someFunctionThatGetsEnum(); // Works only for number-based enums
this.currentDisplay = this.namesToDisplay[enumVal];

и в шаблоне:

<p>{{ currentDisplay  }} </p>

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

0 голосов
/ 21 октября 2018

Кажется, что расхождение было в том, как сервер отправлял данные обратно, currentState на каждом GroceryDto отправлялось в виде строки.Изменение определения enum, как упомянул @Aleksey, решило мою проблему:

export enum State {            
        Archived = "Archived",
        OnShoppingListChecked = "OnShoppingListChecked",
        OnShoppingListUnchecked = "OnShoppingListUnchecked"
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...