向枚举添加函数

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

75286 次浏览

您可以拥有一个独立于 Enum 的类并使用它来获取所需的内容,或者您可以将一个名称空间合并到 Enum 中,并在看起来相同的位置获取所有内容。

模式实用程序类

所以这并不是您想要的,但是它允许您使用静态方法封装“ Mode to string”行为。

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

You can get the string value of an non-const enum by using square brackets:

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

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

This might not work if you are particularly dependent on the underlying enum values. In that case you would need to add a member for the old values and convert places that need it to use the new property.

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

可以使枚举类似于由私有构造函数和静态获取返回对象

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

芬顿溶液的附加物。 如果要在另一个类中使用此枚举数,则需要同时导出枚举和命名空间。它看起来像这样:

export enum Mode {
landscape,
portrait
}


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

然后您只需在类中导入 mode.枚举.ts 文件并使用它。

ExtendedEnum Class

我一直很喜欢 Swift 中的关联类型,并且一直在寻找扩展 Type 脚本枚举基本功能的方法。这种方法背后的思想是在向枚举条目添加更多属性时保留 TypeScript 枚举。建议的类打算将一个对象与一个枚举条目关联,而基本的枚举结构保持不变。

如果您正在寻找一种方法,以便在向每个条目添加更多属性的同时保留普通类型脚本枚举,那么这种方法可能会有所帮助。

Input

enum testClass {
foo = "bar",
anotherFooBar = "barbarbar"
}

输出

{
entries: [
{
title: 'Title for Foo',
description: 'A simple description for entry foo...',
key: 'foo',
value: 'bar'
},
{
title: 'anotherFooBar',
description: 'Title here falls back to the key which is: anotherFooBar.',
key: 'anotherFooBar',
value: 'barbarbar'
}
]
}

实施

export class ExtendedEnum {
entries: ExtendedEnumEntry[] = []


/**
* Creates an instance of ExtendedEnum based on the given enum class and associated descriptors.
*
* @static
* @template T
* @param {T} enumCls
* @param \{\{ [key in keyof T]?: EnumEntryDescriptor }} descriptor
* @return {*}  {ExtendedEnum}
* @memberof ExtendedEnum
*/
static from<T extends Object>(enumCls: T, descriptor: { [key in keyof T]?: EnumEntryDescriptor }): ExtendedEnum {
const result = new ExtendedEnum()
for (const anEnumKey of Object.keys(enumCls)) {
if (isNaN(+anEnumKey)) {   // skip numerical keys generated by js.
const enumValue = enumCls[anEnumKey]
let enumKeyDesc = descriptor[anEnumKey] as EnumEntryDescriptor
if (!enumKeyDesc) {
enumKeyDesc = {
title: enumValue
}
}
result.entries.push(ExtendedEnumEntry.fromEnumEntryDescriptor(enumKeyDesc, anEnumKey, enumValue))
}
}
return result
}
}


export interface EnumEntryDescriptor {
title?: string
description?: string
}


export class ExtendedEnumEntry {
title?: string
description?: string
key: string
value: string | number


constructor(title: string = null, key: string, value: string | number, description?: string) {
this.title = title ?? key // if title is not provided fallback to key.
this.description = description
this.key = key
this.value = value
}


static fromEnumEntryDescriptor(e: EnumEntryDescriptor, key: string, value: string | number) {
return new ExtendedEnumEntry(e.title, key, value, e.description)
}
}

用法

enum testClass {
foo = "bar",
anotherFooBar = "barbarbar"
}


const extendedTestClass = ExtendedEnum.from(testClass, {
foo: {
title: "Title for Foo",
description: "A simple description for entry foo..."
},
anotherFooBar: {
description: "Title here falls back to the key which is: anotherFooBar."
}
})


好处

  • No refactor needed, keep the basic enum structures as is.
  • 您将获得每个枚举条目的代码建议(vs 代码)。
  • 如果在声明枚举描述符(即关联类型)时出现了输入错误,则会得到一个错误。
  • 获得相关类型的好处并保持在 OOP 范例的顶端。
  • 扩展枚举条目是可选的,如果不这样做,这个类将为它生成默认条目。

缺点

This class does not support enums with numerical keys (which shouldn't be annoying, because we usually use enums for human readability and we barely use numbers for enum keys)

将数值分配给键时; 类型脚本对枚举键值进行双重绑定。为防止重复项,此类只考虑字符串键。