【问题标题】:Add functions to an Enum向枚举添加函数
【发布时间】:2015-03-24 21:39:37
【问题描述】:

是否可以在 TypeScript 中为 Enum 类型添加函数?

例如:

enum Mode {
    landscape,
    portrait,

    // the dream...
    toString() { console.log(this); } 
}

或者:

class ModeExtension {
    public toString = () => console.log(this);
}

enum Mode extends ModeExtension {
    landscape,
    portrait,
}

当然,toString() 函数会包含类似 switch 的内容,但用例会遵循以下原则:

class Device {
    constructor(public mode:Mode) {
        console.log(this.mode.toString());
    }
}

我明白为什么扩展 enum 可能是一件奇怪的事情,只是想知道它是否可能。

【问题讨论】:

    标签: enums typescript


    【解决方案1】:

    您可以拥有一个独立于 Enum 的类并使用它来获取您想要的东西,或者您可以将命名空间合并到 Enum 中并在看起来相同的地方获取所有内容。

    模式实用程序类

    所以这并不完全是您所追求的,但这允许您使用静态方法封装“模式到字符串”行为。

    class ModeUtil {
        public static toString(mode: Mode) {
            return Mode[mode];
        }
    }
    

    你可以这样使用它:

    const mode = Mode.portrait;
    const x = ModeUtil.toString(mode);
    console.log(x);
    

    模式枚举/命名空间合并

    您可以将命名空间与 Enum 合并,以便使用其他方法创建看起来像 Enum 的内容:

    enum Mode {
        X,
        Y
    }
    
    namespace Mode {
        export function toString(mode: Mode): string {
            return Mode[mode];
        }
    
        export function parse(mode: string): Mode {
            return Mode[mode];
        }
    }
    
    const mode = Mode.X;
    
    const str = Mode.toString(mode);
    alert(str);
    
    const m = Mode.parse(str);
    alert(m);
    

    【讨论】:

    • 有没有办法给枚举成员添加方法?
    • 使用模块比使用类有什么好处?
    • @Daniel - 我已将答案更新为module 现在是namespace。在这种特殊情况下,我还强调了命名空间的主要好处,即方法出现在枚举下,即Mode
    • @Fenton - 我想import { Mode } from "./Mode.ts" 并以与您的使用示例相同的方式使用它 - 这可能与命名空间合并吗?
    • 值得注意的是,namespace 方法可能会导致使用“枚举”的函数(例如迭代枚举成员以填充选择列表)会产生意外结果,例如“myAddedMethod( ) {...}"。您可以在迭代点过滤掉无关的非枚举成员,但只是指出这种方法并非没有缺点。
    【解决方案2】:

    您可以通过使用方括号来获取非常量枚举的字符串值:

    class Device {
        constructor(public mode:Mode) {
            console.log(Mode[this.mode]);
        }
    }
    

    您也可以将一些特定于枚举的 util 函数放入枚举中,但这就像静态类成员一样:

    enum Mode {
        landscape,
        portrait
    }
    
    namespace Mode {
        export function doSomething(mode:Mode) {
            // your code here
        }
    }
    

    【讨论】:

    • import Mode = require('Mode'); ... /*more code here...*/ <Mode.landscape> landScape = Mode.landscape; 我得到了错误:error TS2503: Cannot find namespace 'Mode'
    • @pawciobiel 好吧,我猜Mode 是您要转换的类型,而不是landscape。将您的演员表从 <Mode.landscape> 更改为 <Mode>
    • 请注意,这在 TS 1.8.10 中不起作用。我必须在模块定义前添加一个export
    • @icfantv 在typescriptlang.org/play上没有变化(在末尾添加Mode.doSomething(Mode.landscape);行进行测试)
    • 我认为这是因为我的枚举也有 export,问题是为了让 TS 合并这两个对象,它们必须要么都被导出,要么都不被导出。很抱歉造成混乱。
    【解决方案3】:

    将您的enum 转换为枚举模式。我发现这对于许多语言来说通常是一种更好的做法,因为否则你会限制你的类型的封装选项。趋势是在枚举值上使用switch,实际上任何依赖于特定枚举值的数据或功能都应该进入枚举的每个实例。我添加了更多代码来演示。

    如果您特别依赖底层枚举值,这可能不起作用。在这种情况下,您需要为旧值添加一个成员,并将需要它的位置转换为使用新属性。

    class Mode {
       public static landscape = new Mode(1920, 1080);
       public static portrait = new Mode(1080, 1920);
    
       public get Width(): number { return this.mWidth; }
       public get Height(): number { return this.mHeight; }
    
       // private constructor if possible in a future version of TS
       constructor(
          private mWidth: number,
          private mHeight: number
       ) {
       }
    
       public GetAspectRatio() {
          return this.mWidth / this.mHeight;
       }
    }
    

    【讨论】:

    • 您自己的例子可以被视为对您的观点的反驳。高度/宽度经常根据其他因素而变化,不仅是“横向与纵向”——它们不属于这个枚举。这个枚举实际上只表达了一种模糊的偏好,它的确切含义取决于上下文。
    • @VsevolodGolovanov 当然,这只是演示如何设置它的示例。我不建议对这些值使用 Mode 枚举。使用与您的项目相关的任何值。
    • 我认为@VsevolodGolovanov 的意思是值对象(如您所建议的)不是枚举,并且无论您使用什么值,它们都不会真正属于枚举。
    • @Christian 他说“宽度”、“高度”和“纵横比”并不是“风景”和“肖像”的真正属性;即:景观的概念与大小无关。这是真的,但这只是一个例子。
    【解决方案4】:

    可以通过私有构造函数和静态获取返回对象来生成枚举

    export class HomeSlideEnum{
    
      public static get friendList(): HomeSlideEnum {
    
        return new HomeSlideEnum(0, "friendList");
    
      }
      public static getByOrdinal(ordinal){
        switch(ordinal){
          case 0:
    
            return HomeSlideEnum.friendList;
        }
      }
    
      public ordinal:number;
      public key:string;
      private constructor(ordinal, key){
    
        this.ordinal = ordinal;
        this.key = key;
      }
    
    
      public getTitle(){
        switch(this.ordinal){
          case 0:
    
            return "Friend List"
          default :
            return "DChat"
        }
      }
    
    }
    

    以后可以这样使用

    HomeSlideEnum.friendList.getTitle();
    

    【讨论】:

      【解决方案5】:

      芬顿解决方案的补充。 如果要在另一个类中使用此枚举器,则需要同时导出枚举和命名空间。它看起来像这样:

      export enum Mode {
          landscape,
          portrait
      }
      
      export namespace Mode {
          export function toString(mode: Mode): string {
              return Mode[mode];
          }
      }
      

      然后你只需在你的类中导入 mode.enum.ts 文件并使用它。

      【讨论】:

      • 谢谢,我正在找这个。
      猜你喜欢
      • 1970-01-01
      • 2020-05-11
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 2020-12-24
      • 1970-01-01
      • 2022-01-18
      相关资源
      最近更新 更多