Website-Suche

Wie filtert man richtig nach Enum-Werten in TypeScript?


Wenn ich ein Enum wie folgt definiert habe:

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

und eine Klasse, die das Enum verwendet:

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

Ich habe etwas Code, der versucht, basierend auf dem currentState von GroceryDto zu filtern, aber es wird nichts qualifiziert, um in das Array aufgenommen zu werden.

//...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

Ich konnte das gewünschte Ergebnis erzielen, indem ich in einen String umgewandelt habe, aber das sollte unnötig sein, wenn ich TypeScript verwende.

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

Antwort #1

Es scheint, dass die Diskrepanz darin lag, wie der Server die Daten zurückgesendet hat, currentState auf jedem GroceryDto wurde als String gesendet. Die Änderung der Enum-Definition wie von @Aleksey erwähnt hat mein Problem gelöst:

export enum State {            
        Archived = "Archived",
        OnShoppingListChecked = "OnShoppingListChecked",
        OnShoppingListUnchecked = "OnShoppingListUnchecked"
    }

Antwort #2

Seien Sie darauf hingewiesen, dass enum in TypeScript ziemlich... nun ja, sie könnten missverstanden werden und immer sowohl als string-basierter als auch numerischer Typ verwendet werden könnten.

Wenn Sie Ihr enum in einem Formular so verwenden, wie Sie es vorgestellt haben:

State.OnShoppingListUnchecked

Dann wird es als Zahl dargestellt und mit dem numerischen Wert von 1 verglichen. Betrachten Sie jedoch den folgenden Enum-Code zum Cross-Matching:

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 

Wahrscheinlich erhalten Sie vom Server eine Zeichenkette und keine Zahl, und deshalb schlagen Ihre Prüfungen fehl. Sie können dieser Überprüfung ein wenig Automatisierung auf folgende Weise hinzufügen:

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
}

Um sicherzustellen, dass Sie unabhängig davon, ob es sich um einen Eingabestring oder eine Zahl handelt, immer mit dem richtigen enum-Eintrag vergleichen.

Und beachten Sie, dass stringbasierte Enums seit TypeScript 2.4 und höher unterstützt werden, und meiner persönlichen Meinung nach sollte deren Verwendung minimiert werden, hauptsächlich deshalb, weil zahlbasierte Enums eine bequeme Möglichkeit sind, zusätzliche Informationen aus array-artigen Strukturen auszuwählen, während stringbasierte auf diese Weise nicht verwendet werden können:

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];

und in der Vorlage:

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

Wenn Sie kein Anwendungsfall-Szenario für Array-Indizierung haben, können stringbasierte Enums durch String-Literaltypen ersetzt werden, die Ihnen die gleichen Vorteile wie Enums bieten, jedoch mit weniger Sorgen über Typ- und Kompatibilitätsprobleme.

Verwandte Artikel