枚举作为 TypeScript 中的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30774874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Enum as Parameter in TypeScript
提问by Synoon
Isn't it possible to set the type of a parameter to an Enum? Like this:
是否可以将参数的类型设置为 Enum?像这样:
private getRandomElementOfEnum(e : enum):string{
var length:number = Object.keys(e).length;
return e[Math.floor((Math.random() * length)+1)];
}
If I do that, Intellij mark this code as unknown. And suggest to rename the variable, does that make sense?
如果我这样做,Intellij 会将此代码标记为未知。并建议重命名变量,这有意义吗?
private getRandomElementOfEnum(e : any):string{
var length:number = Object.keys(e).length;
return e[Math.floor((Math.random() * length)+1)];
}
This Code works fine. but isn't as elegant and code-convential.
此代码工作正常。但没有那么优雅和代码约定俗成。
Is there a possibility or a little workaround to define an enum as a parameter?
是否有可能或一些解决方法将枚举定义为参数?
EDIT:
编辑:
After studying those answers, Can I do this also with ah set of defined enum, sth similar to enum1|enum2|enum3?
在研究了这些答案之后,我也可以用一组定义的枚举来做到这一点,类似于 enum1|enum2|enum3 吗?
采纳答案by Paleo
It's not possible to ensure the parameter is an enum, because enumerations in TS don't inherit from a common ancestor or interface.
无法确保参数是枚举,因为 TS 中的枚举不是从公共祖先或接口继承的。
TypeScript brings static analysis. Your code uses dynamic programming with Object.keys
and e[dynamicKey]
. For dynamic codes, the type any
is convenient.
TypeScript 带来了静态分析。您的代码使用带有Object.keys
和 的动态编程e[dynamicKey]
。对于动态代码,类型any
很方便。
Your code is buggy: length()
doesn't exists, e[Math.floor((Math.random() * length)+1)]
returns a string or an integer, and the enumeration values can be manually set…
你的代码有问题:length()
不存在,e[Math.floor((Math.random() * length)+1)]
返回一个字符串或一个整数,枚举值可以手动设置......
Here is a suggestion:
这是一个建议:
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));
Ideally, the parameter type any
should be replaced by typeof E
but the compiler (TS 1.5) can't understand this syntax.
理想情况下,参数类型any
应该替换为typeof E
但编译器(TS 1.5)无法理解此语法。
回答by Ryan Cavanaugh
You can do better than any
:
你可以做得比any
:
enum E1 {
A, B, C
}
enum E2 {
X, Y, Z
}
function getRandomElementOfEnum(e: { [s: number]: string }): number {
/* insert working implementation here */
return undefined;
}
// OK
var x: E1 = getRandomElementOfEnum(E1);
// Error
var y: E2 = getRandomElementOfEnum(window);
// Error
var z: string = getRandomElementOfEnum(E2);
回答by Thilo
I agree with @Tarh. Enums in TypeScript are just Javascript objects without a common interface or prototype (and if they are const enum
, then they are not even objects), so you cannot restrict types to "any enum".
我同意@Tarh。TypeScript 中的枚举只是没有通用接口或原型的 Javascript 对象(如果它们是const enum
,那么它们甚至不是对象),因此您不能将类型限制为“任何枚举”。
The closest I could get is something like the following:
我能得到的最接近的是以下内容:
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))];
}
This works for all enums (without custom initializers), but it would also accept other arrays as input (and then fail because the method body relies on the very specific key structure that TypeScript enums have).
这适用于所有枚举(没有自定义初始值设定项),但它也会接受其他数组作为输入(然后失败,因为方法主体依赖于 TypeScript 枚举具有的非常特定的键结构)。
So unless you have a real need for such a "generic" function, make typesafe functions for the individual enum types (or a union type like E1|E2|E3
) that you actually need.
因此,除非您确实需要这样的“通用”函数,否则请为您实际需要的各个枚举类型(或类似的联合类型E1|E2|E3
)创建类型安全函数。
And if you do have this need (and this might very well be an X-Y-problem that can be solved in a better, completely different way given more context), use any
, because you have left typesafe territory anyway.
如果你确实有这个需求(这很可能是一个 XY 问题,可以在给定更多上下文的情况下以更好、完全不同的方式解决),请使用any
,因为无论如何你已经离开了类型安全的领域。
回答by Valeriy Katkov
Summing up the previous answers with some new syntax - a generic typesafe function, which works with numeric enums as well as string enums:
用一些新语法总结以前的答案 - 一个通用的类型安全函数,它适用于数字枚举和字符串枚举:
function getRandomElementOfEnum<T extends {[key: number]: string | number}>(e: T): T[keyof T] {
const keys = Object.keys(e);
const randomKeyIndex = Math.floor(Math.random() * keys.length);
const randomKey = keys[randomKeyIndex];
// Numeric enums members also get a reverse mapping from enum values to enum names.
// So, if a key is a number, actually it's a value of a numeric enum.
// see https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings
const randomKeyNumber = Number(randomKey);
return isNaN(randomKeyNumber)
? e[randomKey as keyof T]
: randomKeyNumber as unknown as T[keyof T];
}
回答by selinathat
Another possible option not mentioned above is using the actual values. This is however possible only when you know all the options. This, in my opinion is definitely better than any.
上面没有提到的另一个可能的选择是使用实际值。然而,只有当您知道所有选项时,这才是可能的。在我看来,这绝对比任何一个都好。
doSomething(a: string, b: 'this'|'can'|'work'): void {
//do something
}
回答by MajiD
@selinathat's solution is great only if you have few types. but what if we have more ? for example :
@selinathat 的解决方案只有在您的类型很少时才很好。但是如果我们有更多呢?例如 :
doSomething(a: string, b: 'this'|'can'|'work'|'test1'|'test2'|'test3'): void {
//do something
}
its pretty ugly hah !? i prefer to use keyof:
好丑哈!?我更喜欢使用keyof:
interface Items {
'this',
'can',
'work',
'test1',
'test2',
'test3',
}
doSomething(a: string, b: keyof Items): void {
//do something
}
回答by koldoon
May be this trick will fit:
可能这个技巧适合:
enum AbstractEnum { // put somewhere in hidden scope
}
private getRandomElementOfEnum(e: typeof AbstractEnum) {
...
}