枚举中的枚举作为参数

时间:2015-06-11 07:56:00

标签: enums typescript

是否可以将参数类型设置为枚举?像这样:

private getRandomElementOfEnum(e : enum):string{
    var length:number = Object.keys(e).length;
    return e[Math.floor((Math.random() * length)+1)];
}

如果我这样做,Intellij会将此代码标记为未知。并建议重命名变量,这有意义吗?

private getRandomElementOfEnum(e : any):string{
    var length:number = Object.keys(e).length;
    return e[Math.floor((Math.random() * length)+1)];
}

本规范正常。但不像优雅和代码传统。

是否有可能或稍微解决方法将枚举定义为参数?

编辑:

在研究了那些答案之后,我是否可以使用一组定义的enum来做这个,类似于enum1 | enum2 | enum3?

10 个答案:

答案 0 :(得分:14)

无法确保参数是枚举,因为TS中的枚举不会从公共祖先或接口继承。

TypeScript带来静态分析。您的代码使用Object.keyse[dynamicKey]进行动态编程。对于动态代码,类型any很方便。

您的代码有问题:length()不存在,e[Math.floor((Math.random() * length)+1)]返回字符串或整数,the enumeration values can be manually set ...

这是一个建议:

function getRandomElementOfEnum<E>(e: any): E {
    var keys = Object.keys(e),
        index = Math.floor(Math.random() * keys.length),
        k = keys[index];
    if (typeof e[k] === 'number')
        return <any>e[k];
    return <any>parseInt(k, 10);
}

function display(a: Color) {
    console.log(a);
}

enum Color { Blue, Green };
display(getRandomElementOfEnum<Color>(Color));

理想情况下,参数类型any应替换为typeof E,但编译器(TS 1.5)无法理解此语法。

答案 1 :(得分:14)

你可以做得比template更好:

any

答案 2 :(得分:5)

我同意@Tarh。 TypeScript中的枚举只是没有通用接口或原型的Javascript对象(如果它们是const enum,那么它们甚至不是对象),因此您不能将类型限制为“任何枚举”。

我能得到的最接近的是:

enum E1 {
    A, B, C
}
enum E2 {
    X, Y, Z
}

// make up your own interface to match TypeScript enums
// as closely as possible (not perfect, though)
interface Enum {
    [id: number]: string
}

function getRandomElementOfEnum(e: Enum): string {
   let length = Object.keys(e).length / 2;
   return e[Math.floor((Math.random() * length))];
}

这适用于所有枚举(没有自定义初始值设定项),但它也会接受其他数组作为输入(然后失败,因为方法体依赖于TypeScript枚举所具有的特定键结构)。

因此,除非您真正需要这样的“通用”函数,否则请为您实际需要的各个枚举类型(或类似E1|E2|E3的联合类型)创建类型安全函数。

如果你确实有这个需求(这很可能是一个XY问题,可以在给定更多上下文的情况下以更好,完全不同的方式解决),使用any,因为你已经离开了类型安全区域反正。

答案 3 :(得分:2)

上面未提及的另一个可能的选择是使用实际值。但是,只有当您知道所有选项时才有可能。我认为,这绝对比任何一个都要好。

    doSomething(a: string, b: 'this'|'can'|'work'): void {
     //do something
    }

答案 4 :(得分:2)

使用一些新语法总结以前的答案-泛型类型安全函数,可与数字枚举以及字符串枚举一起使用:

 Resources res = getBaseContext().getResources();
        int id = R.drawable.landscape;
        Bitmap src = BitmapFactory.decodeResource(res, id);
        Bitmap dest = src.copy(Bitmap.Config.ARGB_8888,true);


        for (int i = 0; i < dest.getWidth(); i++) {
            for (int j = 0; j < dest.getHeight(); j++) {
                int color = src.getPixel(i,j);
                color = color & 0xFFC08080;
                dest.setPixel(i,j,color);
            }
        }

答案 5 :(得分:2)

也许这个技巧适合:

enum AbstractEnum { // put somewhere in hidden scope
}

private getRandomElementOfEnum(e: typeof AbstractEnum) {
    ...
}

答案 6 :(得分:1)

@selinathat解决方案只有在类型很少的情况下才有用。但是,如果我们还有更多呢?例如:

doSomething(a: string, b: 'this'|'can'|'work'|'test1'|'test2'|'test3'): void {
 //do something
}

它非常难看哈!! 我更喜欢使用 keyof

interface Items {
    'this',
    'can',
    'work',
    'test1',
    'test2',
    'test3',
}

doSomething(a: string, b: keyof Items): void {
 //do something
}

答案 7 :(得分:0)

这里是一个示例,该示例允许使用泛型传递带有该枚举经过类型检查的值的枚举。这实际上是对此处稍有不同的问题的回答,该问题被标记为重复:Typescript how to pass enum as Parameter

enum Color {
    blue,
};
enum Car {
    cadillac,
};
enum Shape {
    square,
}

type SupportedEnums = typeof Color | typeof Car;

type InvertTypeOf<T> = T extends typeof Color ? Color :
    T extends typeof Car ? Car : never;

function getText<T extends SupportedEnums>(enumValue: InvertTypeOf<T>, typeEnum: T) string | undefined {
  if (typeEnum[enumValue]) {
    return `${enumValue}(${typeEnum[enumValue]})`;
  }
}

console.log(getText(Car.cadillac, Car)); // 0(cadillac)
console.log(getText(0, Color)); // 0(red)
console.log(getText(4, Color)); // undefined

// @ts-expect-error Color is not Car
console.log(getText(Color.blue, Car));

// @ts-expect-error Car is not a Color
console.log(getText(Car.toyota, Color));

// @ts-expect-error  Shape is not in SupportedEnums
console.log(getText(5, Shape));

// @ts-expect-error  Shape is not in SupportedEnums
console.log(getText(Shape.square, Shape));

答案 8 :(得分:0)

在TypeScript 3.9.7上测试

解决方案

type EnumTypeString<TEnum extends string> =
    { [key in string]: TEnum | string; }

type EnumTypeNumber<TEnum extends number> =
    { [key in string]: TEnum | number; }
    | { [key in number]: string; }

type EnumType<TEnum extends string | number> =
    (TEnum extends string ? EnumTypeString<TEnum> : never)
    | (TEnum extends number ? EnumTypeNumber<TEnum> : never)

type EnumOf<TEnumType> = TEnumType extends EnumType<infer U>
    ? U
    : never

用法

枚举类型:
function forEachEnum<TEnum extends string | number>(
    enumType: EnumType<TEnum>,
    callback: (value: TEnum, key: string) => boolean|void,
) {
    for (let key in enumType) {
        if (Object.prototype.hasOwnProperty.call(enumType, key) && isNaN(Number(key))) {
            const value = enumType[key] as any
            if (callback(value, key)) {
                return
            }
        }
    }
}
EnumOf:
function forEachEnum2<TEnumType>(
    enumType: TEnumType,
    callback: (value: EnumOf<TEnumType>, key: string) => boolean|void,
) {
    for (let key in enumType) {
        if (Object.prototype.hasOwnProperty.call(enumType, key) && isNaN(Number(key))) {
            const value = enumType[key] as any
            if (callback(value, key)) {
                return
            }
        }
    }
}

测试

enum EnumAsString {
    Value1 = 'value 1',
    Value2 = 'value 2',
}

enum EnumAsNumber {
    Value1 = 1,
    Value2 = 2,
}

// Error
let sn: EnumType<string> = EnumAsNumber

// Correct
let ns: EnumType<number> = EnumAsString // I have not found a solution for the error here
let nn: EnumType<number> = EnumAsNumber
let Nn: EnumType<EnumAsNumber> = EnumAsNumber
let ss: EnumType<string> = EnumAsString
let Ss: EnumType<EnumAsString> = EnumAsString

forEachEnum(EnumAsString, value => {
    let e: EnumAsString = value
    let s: string = value
    let n: number = value // Error
})

forEachEnum(EnumAsNumber, value => {
    let e: EnumAsNumber = value
    let s: string = value // Error
    let n: number = value
})

forEachEnum2(EnumAsString, value => {
    let e: EnumAsString = value
    let s: string = value
    let n: number = value // Error
})

forEachEnum2(EnumAsNumber, value => {
    let e: EnumAsNumber = value
    let s: string = value // Error
    let n: number = value
})

答案 9 :(得分:0)

我遇到了同样的问题,我做到了

  private getOptionsFromEnum(OptionEnum: Record<string, string>): Array<SelectOption> {
    return Object.keys(OptionEnum).map((value) => {
      return {
        name: OptionEnum[value],
        value,
      } as SelectOption;
    });
  }