【问题标题】:Add description attribute to enum and read this description in TypeScript将描述属性添加到枚举并在 TypeScript 中阅读此描述
【发布时间】:2018-11-19 22:04:32
【问题描述】:

我想知道如何在 TypeScript 中为枚举添加描述属性。 我想创建如下枚举(或类似的东西):

public enum Sample
{
    [Display(Name = "Blah V")]
    V,

    [Display(Name = " Blah IV")]
    IV,

    [Display(Name = " Blah III")]
    III,
}

为了能够对此类枚举执行基本操作,我将创建通用 EnumHelper。这个帮助类应该包含允许:获取描述值、获取名称和数值的方法。问题是如何在打字稿中实现这一点?如果无法向枚举添加属性,有什么办法吗? 我希望能够:

-  get number of enum value,
-  get description value,
-  get the name of enum field.

例如对于 Sample.IV,它将是:

1, 
Blah IV, 
IV.

【问题讨论】:

    标签: typescript ecmascript-6 enums


    【解决方案1】:

    另一个有趣的解决方案founded here 是使用 ES6 Map:

    export enum Sample {
      V,
      IV,
      III
    }
    
    export const SampleLabel = new Map<number, string>([
      [Sample.V, 'FIVE'],
      [Sample.IV, 'FOUR'],
      [Sample.III, 'THREE']
    ]);
    

    使用

    console.log(SampleLabel.get(Sample.IV)); // FOUR
    

    【讨论】:

      【解决方案2】:

      以下方法将是类型安全的(自动完成工作)并且它使用普通对象。它基于this feature of TypeScript

      export enum Sample {
        I = 1,
        II = 2,
        III = 3
      }
      
      export const SampleLabel: { [key in Sample]: string } = {
        [Sample.I]: "ONE",
        [Sample.II]: "TWO",
        [Sample.III]: "THREE",
      };
      

      【讨论】:

      • 这比地图解决方案 IMO 更优雅。如果您错过了 SampleLabel 中的一个键,我认为还应该给您一个编译错误吗?
      【解决方案3】:

      TypeScript 不允许您向 enum 元素添加属性,该元素在运行时只是一个原始字符串或数字。相反,您必须执行一些操作,例如创建一个新类型,该类型包含对这些元素的引用,并且还具有您想要的方法或属性。

      这是一种可能的方法。从您的普通enum 开始,如下所示:

      enum SampleEnum {
        V, IV, III
      }
      

      让我们为您的扩展类型定义一个接口。它有一个name、一个description 和一个number。请注意,此类型是通用类型,因此我们可以很快缩小 namenumber 类型:

      interface ISample<N extends number, S extends string> {
        readonly name: S;
        readonly description: string;
        readonly number: N;
      }
      

      这是一个函数,它可以获取您的 SampleEnum 对象并返回具有相同键但具有实现扩展接口的值的内容:

      function makeSample<E extends Record<Extract<keyof E, string>, number>>(
        mapping: E
      ): { [K in Extract<keyof E, string>]: ISample<E[K], K> } {
        const ret = {} as { [K in Extract<keyof E, string>]: ISample<E[K], K> };
        (Object.keys(mapping).filter(k => k !== (+k) + "") as
          (Extract<keyof E, string>)[]
        ).forEach(k => {
          ret[k] = {
            name: k,
            description: "Blah " + k,
            number: mapping[k]
          }
        });
        return ret;
      }
      

      这可能是很多类型的杂耍,但它基本上只是从SampleEnum 中提取字符串值键(并忽略在运行时将数字键添加到数字枚举的reverse mapping)并构建扩展的实例每个接口,以某种类型安全的方式。

      最后,让我们创建代表enumSample 值和类型:

      const Sample = makeSample(SampleEnum);
      type Sample = (typeof Sample)[keyof typeof Sample]
      

      好的,让我们使用它:

      const nameOfIV = Sample.IV.name; // "IV"
      console.log(nameOfIV); // "IV"
      const numberOfIII = Sample.III.number; // SampleEnum.III
      console.log(numberOfIII); // 1
      const descriptionOfV = Sample.V.description; // string
      console.log(descriptionOfV); // "Blah V"
      
      const goodSample: Sample = Sample.III; // okay
      const badSample: Sample = {
        name: "II", 
        description: "oops", 
        number: 3
      }; // error, name doesn't match
      

      在我看来是合理的。 See for yourself。当然还有其他方法可以解决它,但这应该会给你一个想法。希望有帮助。祝你好运!

      【讨论】:

      • 我问这个问题的主要原因是要了解如何将带有描述的 C# 枚举传输到角度选择器,其中值是枚举的值,名称是枚举的描述。可能在这种情况下,将 c# 枚举转换为 typescript 类会更好、更容易。感谢您提供非常详细的回答!
      【解决方案4】:

      已接受答案的变体。将 number 替换为您的 enum 类型以更安全。

       export enum Sample {
            V,
            IV,
            III
          }
      
      export const SampleLabel = new Map<Sample, string>([
        [Sample.V, 'FIVE'],
        [Sample.IV, 'FOUR'],
        [Sample.III, 'THREE']
      ]);
      

      【讨论】:

        【解决方案5】:

        这种模式对我有用:

        export enum PriceTypes {
            Undefined = 0,
            UndefinedDescription = 'Undefined' as any,
            UserEntered = 1,
            UserEnteredDescription = 'User Entered' as any,
            GeneratedFromTrade = 2,
            GeneratedFromTradeDescription = 'Generated From Trade' as any,
            GeneratedFromFreeze = 3,
            GeneratedFromFreezeDescription = 'Generated Rom Freeze' as any
        }
        

        ...

            GetDescription(e: any, id: number): string {
                return e[e[id].toString() + "Description"];
            }
            getPriceTypeDescription(price: IPricePoint): string {
                return this.GetDescription(PriceTypes, price.priceType);
            }
        

        【讨论】:

        • 枚举使用不当。 UndefinedDescription 不是有效的 PriceType。
        猜你喜欢
        • 1970-01-01
        • 2018-12-18
        • 1970-01-01
        • 2011-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多