Hvordan filtrerer man korrekt efter enum-værdi i Typescript?


Hvis jeg har en enum defineret sådan her:

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

og en klasse, der bruger enum'en:

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

Jeg har noget kode, der forsøger at filtrere baseret på currentState af GroceryDto, men som ikke kvalificerer noget til at blive indsat i arrayet.

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

Jeg kunne få det resultat, jeg ønskede, ved at kaste til en streng, men det virker som om, det burde være unødvendigt, hvis jeg bruger Typescript.

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

Svar #1

Det ser ud til, at uoverensstemmelsen var i, hvordan serveren sendte dataene tilbage, currentState på hver GroceryDto blev sendt som en streng. Ændring af enum-definitionen som @Aleksey nævnte løste mit problem:

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

Svar #2

Vær opmærksom på, at enuma i TypeScript er ret... ja, de kan misforstås, og de kan altid bruges som string-baserede og numerisk-baserede typer.

Hvis du bruger din enum i formen, som du præsenterede:

State.OnShoppingListUnchecked

Så vil det blive repræsenteret som et tal og sammenlignet med den numeriske værdi 1. Men overvej følgende kode for krydsmatchende enum:

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 

Sandsynligvis får du en streng fra server-siden, ikke et tal, og derfor fejler dine kontroller. Du kan tilføje lidt automatisering til den kontrol på følgende måde:

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
}

For at sikre, uanset om det er en inputstreng eller et tal, vil du altid sammenligne med den korrekte enum-post.

Og husk, strengbaserede enums er understøttet siden TypeScript 2.4 og opefter, og efter min personlige mening bør brugen af dem minimeres, mest fordi talbaserede enums er en bekvem måde at vælge nogle yderligere oplysninger fra array-arrangerede strukturer, mens strengbaserede ikke kan bruges på denne måde:

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

og i skabelon:

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

Hvis du ikke har brug for et anvendelsesscenarie for array-indeksering, kan streng-baserede enums erstattes med String Literal Types med de samme fordele som enums giver dig, men med mindre bekymring om type- og kompatibilitetsproblemer.

Relaterede artikler