是否可以将参数类型设置为枚举?像这样:
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?
答案 0 :(得分:14)
无法确保参数是枚举,因为TS中的枚举不会从公共祖先或接口继承。
TypeScript带来静态分析。您的代码使用Object.keys
和e[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;
});
}