如何在 Typescript 中创建嵌套枚举

How do I create nested enums in Typescript

Java程序员在这里。我正在设置某种嵌套枚举结构。下面是我正在处理的简短注释示例。我知道如何在 Java 中解决这个问题,但我不知道如何在 Typescript 中解决这个问题。

基本上我有一个 EntityNames 列表,每个 entityName 都有一堆 entityTypeNames。我想创建 functions/methods 接受 entityTypeName 作为参数,并且可以执行一些逻辑,也可以找到属于此 EntityTypeName 的 entityName。重要的是轻松地将参数传递给这些 functions/methods 而没有冗余。目前我正在传递 entityName 和 entityTypeName,这是多余的。

(我使用的是 typescript 4.5.4)

export class Afs {
  public static oneMethod(entityName: Afs.EntityName) {
    // This method just uses the entityName.
  }

  public static someMethod(entityTypeName: Afs.EntityTypeName) {
    // This method uses the entityTypeName and
    // the entityName. However, passing both
    // feels redundant. How to get the entityNames 
    // here, without passing the entityName argument?
  }

}

export namespace Afs {

  export enum EntityName {
    // Simplified. Much more entitynames.
    address = 'address',
    condition = 'condition',
  }

  /* In Java I would create an EntityTypeName 
  ** interface that is implemented by the enums 
  ** with a static method getEntityName() */
  export type EntityTypeName = EntityTypeName.Address 
  | EntityTypeName.Condition


  // I would implement the interface here.
  export namespace EntityTypeName {
    export enum Address {
      default = 'default',
      // enum method from interface 
      // getEntityName() { return Afs.EntityName.Address }
    }
  
    export enum Condition {
      // Simplified. Much more 
      conditionDetails = "conditionDetails",
      employmentConditions = "employmentConditions",
    }  
  }

}

更新

我尝试了@mike-clark 的解决方案,这很有效! (谢谢!!!)但是看起来有很多代码重复,我希望有一个更简单的解决方案。现实世界有 29 个实体名称和 350 多个实体类型名称。

export class Afs {
  public static oneMethod(entityName: Afs.EntityName) {
    console.log(entityName.get());
  }
  public static someMethod(entityTypeName: Afs.EntityTypeName.Generic) {
    console.log(entityTypeName.getEntityName().get());
    console.log(entityTypeName.get());
  }
}

export namespace Afs {

  export class EntityName {
    public static address = new EntityName('address');
    public static condition = new EntityName('condition');
    private constructor(private entityName: string) { }
    public get(): string {
      return this.entityName
    }
  }

  export namespace EntityTypeName {

    export interface Generic {
      get(): string;
      getEntityName(): EntityName;
    }

    export class Address implements Generic {
      public static default = new Address(EntityName.address, 'default');
      private constructor(private entityName: EntityName, private entityTypeName: string) {}
      get(): string { return this.entityTypeName }
      getEntityName(): EntityName { return this.entityName }
    }

    export class Condition implements Generic {
      public static conditionDetails = new Condition(EntityName.condition, 'conditionDetails');
      public static employeeConditions = new Condition(EntityName.condition, 'employeeConditions')
      private constructor(private entityName: EntityName, private entityTypeName: string) {}
      get(): string { return this.entityTypeName }
      getEntityName(): EntityName { return this.entityName }
    }

  }

}

您不能在 TypeScript 中添加可在 enum 成员上调用的方法。尽管令人失望(在面向对象的意义上),但通常使用的实际解决方案是打开枚举并处理所有情况的外部静态实用函数。

,这是一种分组和跟踪可帮助您使用枚举“元数据”的实用函数的便捷方式。

。但是这些不是 first-class TypeScript enums,尽管在大多数情况下它们是足够的替代品。放弃内置的 enum 来代替您自己制作的东西确实令人失望,但这是人们确实使用的模式。

目前的技术原因是,附加到每个枚举键的值是一个字符串文字,它没有仅由枚举的键值共享的通用原型。鉴于此 TypeScript:

enum MyEnum {
    A='A',
    B='B'
}

生成的JavaScript代码是:

var MyEnum;
(function (MyEnum) {
    MyEnum["A"] = "A";
    MyEnum["B"] = "B";
})(MyEnum || (MyEnum = {}));

如您所见,成员值没有通用原型或 class,因此我们无法“破解”我们的方法来向成员值添加函数,除非我们扩展全局字符串 class本身,这是一个坏主意。 TypeScript 需要通过用通用原型(或至少是通用接口——明示或暗示)将成员值字符串包装在第二个 class 中来使枚举的设计复杂化,我猜语言设计者没有想要介绍这种复杂程度。