【问题标题】:How to properly filter by enum value in Typescript?如何在 Typescript 中按枚举值正确过滤?
【发布时间】:2018-10-21 15:55:32
【问题描述】:

如果我有这样定义的枚举:

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;

我有一些代码试图根据 currentStateGroceryDto 进行过滤,但没有限定要输入到数组中的任何内容。

//...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]
);

【问题讨论】:

  • activeGroceries 中的数据是什么样的?也许您是从服务器获取strings,而不是枚举值(似乎是数字)
  • 如果您从网络调用中获得的值是字符串(而且看起来是) - 您可以使用字符串枚举:enum State { Archived = 'Archived' ... }
  • 你们都说对了,GroceryDto 中的public currentState: State = null; 是作为字符串而不是枚举从服务器序列化的。

标签: typescript enums filtering


【解决方案1】:

似乎差异在于服务器发送回数据的方式,每个GroceryDto 上的currentState 被作为字符串发送。像@Aleksey 提到的那样更改枚举定义解决了我的问题:

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

【讨论】:

    【解决方案2】:

    请注意,TypeScript 中的 enuma 相当……他们可能会被误解,并且总是可能被用作基于字符串和基于数字的类型。

    如果您使用您的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>
    

    如果您没有数组索引的用例场景,则可以将基于字符串的枚举替换为字符串文字类型,其优点与枚举相同,但无需担心类型和兼容性问题。

    【讨论】:

      猜你喜欢
      • 2020-09-24
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多