向枚举添加函数


78

是否可以在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可能是一件奇怪的事情,只是想知道是否有可能。

Answers:


101

您可以拥有一个与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);

4
有没有一种方法可以将方法添加到枚举成员?
杰伊·威克

使用模块优于类有什么好处吗?
丹尼尔(Daniel)

2
@Daniel -因为我已经更新了答案module现在namespace。我还强调了在这种特殊情况下命名空间的主要好处,即出现在枚举下的方法,即Mode
芬顿

@Fenton-我想以import { Mode } from "./Mode.ts"与您的用法示例相同的方式使用它-合并名称空间是否可能?
Vedran '18

1
值得注意的是,该namespace方法可能会导致消耗“枚举”的函数(例如,迭代枚举成员以填充选择列表)会产生问题,将产生意外结果,例如“ myAddedMethod(){...}”。您可以在迭代点过滤掉多余的非枚举成员,但要指出这种方法并非没有缺点。
virtualeyes

30

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

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
    }
}

1
import Mode = require('Mode'); ... /*more code here...*/ <Mode.landscape> landScape = Mode.landscape;而且我得到了一个错误: error TS2503: Cannot find namespace 'Mode'
pawciobiel 2015年

1
@pawciobiel好吧,我想这Mode是您要转换为的类型,而不是landscape。将演员表从更改<Mode.landscape><Mode>
Benjamin

请注意,这在TS 1.8.10中不起作用。我必须export在模块定义前面添加一个。
icfantv

@icfantv它适用于不变typescriptlang.org/play(添加线Mode.doSomething(Mode.landscape);在端部,用于测试)
本杰明

1
我认为这是因为我的枚举也有export,问题是,要让TS合并两个对象,必须将两者都导出,或者两者都不能导出。对困惑感到抱歉。
icfantv

12

将您转换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;
   }
}

1
您自己的示例可以视为您观点的反驳。高度/宽度通常会因其他因素而有所不同,而不仅仅是“风景与肖像”-它们不属于此枚举。该枚举实际上仅表示模糊的偏好,其确切含义取决于上下文。
Vsevolod Golovanov

1
@VsevolodGolovanov当然,这只是一个演示如何设置它的示例。我不建议对Mode这些值使用枚举。使用与您的项目相关的任何值。
Dave Cousineau

我认为@VsevolodGolovanov所说的是,值对象(如您建议的那样)不是枚举,并且无论您使用什么值,它们都不会真正属于枚举。
克里斯蒂安

1
@克里斯蒂安,他说的是“宽度”,“高度”和“长宽比”并不是“风景”和“肖像”的真正属性;即:景观的概念与大小无关。的确如此,但这只是一个例子。
Dave Cousineau

2

可以使枚举像私有构造函数和静态获取返回对象一样

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();

0

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

export enum Mode {
    landscape,
    portrait
}

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

然后,您只需在类中导入mode.enum.ts文件并使用它即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.