是不是可以将参数类型设置为枚举?像这样:
private getRandomElementOfEnum(e : enum):string{
var length:number = Object.keys(e).length;
return e[Math.floor((Math.random() * length)+1)];
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做,Intellij会将此代码标记为未知.并建议重命名变量,这有意义吗?
private getRandomElementOfEnum(e : any):string{
var length:number = Object.keys(e).length;
return e[Math.floor((Math.random() * length)+1)];
}
Run Code Online (Sandbox Code Playgroud)
本规范运作正常.但不像优雅和代码方便.
是否有可能或稍微解决方法将枚举定义为参数?
编辑:
在研究了这些答案之后,我是否可以使用一组定义的枚举来做到这一点,类似于enum1 | enum2 | enum3?
Pal*_*leo 17
不可能确保参数是枚举,因为TS中的枚举不会从公共祖先或接口继承.
TypeScript带来了静态分析.您的代码使用动态规划与Object.keys和e[dynamicKey].对于动态代码,类型any很方便.
您的代码有错误:length()不存在,e[Math.floor((Math.random() * length)+1)]返回字符串或整数,并且可以手动设置枚举值 ...
这是一个建议:
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));
Run Code Online (Sandbox Code Playgroud)
理想情况下,参数类型any应该替换为typeof E但编译器(TS 1.5)无法理解此语法.
Rya*_*ugh 17
你可以做得比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);
Run Code Online (Sandbox Code Playgroud)
Val*_*kov 14
用一些新语法总结以前的答案 - 一个通用的类型安全函数,它适用于数字枚举和字符串枚举:
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];
}
Run Code Online (Sandbox Code Playgroud)
Thi*_*ilo 10
我同意@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))];
}
Run Code Online (Sandbox Code Playgroud)
这适用于所有枚举(没有自定义初始值设定项),但它也会接受其他数组作为输入(然后失败,因为方法体依赖于TypeScript枚举所具有的非常特定的键结构).
因此,除非您真正需要这样的"通用"函数,否则请为您实际需要的各个枚举类型(或类似的联合类型E1|E2|E3)创建类型安全函数.
如果你确实有这个需求(这很可能是一个XY问题,可以通过更好的,完全不同的方式解决更多的上下文),请使用any,因为你无论如何都已经离开了类型安全区域.
小智 6
也许这个技巧适合:
enum AbstractEnum { // put somewhere in hidden scope
}
private getRandomElementOfEnum(e: typeof AbstractEnum) {
...
}
Run Code Online (Sandbox Code Playgroud)
在 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
Run Code Online (Sandbox Code Playgroud)
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
枚举:
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
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
})
Run Code Online (Sandbox Code Playgroud)
小智 5
上面没有提到的另一个可能的选择是使用实际值。然而,只有当您知道所有选项时,这才是可能的。在我看来,这绝对比任何一个都好。
doSomething(a: string, b: 'this'|'can'|'work'): void {
//do something
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30092 次 |
| 最近记录: |