'How to get a random enum in TypeScript?
How to get a random item from an enumeration?
enum Colors {
Red, Green, Blue
}
function getRandomColor(): Color {
// return a random Color (Red, Green, Blue) here
}
Solution 1:[1]
Most of the above answers are returning the enum keys, but don't we really care about the enum values?
If you are using lodash, this is actually as simple as:
_.sample(Object.values(myEnum)) as MyEnum
The casting is unfortunately necessary as this returns a type of any. :(
If you're not using lodash, or you want this as its own function, we can still get a type-safe random enum by modifying @Steven Spungin's answer to look like:
function randomEnum<T>(anEnum: T): T[keyof T] {
const enumValues = (Object.values(anEnum) as unknown) as T[keyof T][];
const randomIndex = Math.floor(Math.random() * enumValues.length);
return enumValues[randomIndex];
}
Solution 2:[2]
How about this, using Object.values from es2017 (not supported by IE and support in other browsers is more recent):
function randEnumValue<T>(enumObj: T): T[keyof T] {
const enumValues = Object.values(enumObj);
const index = Math.floor(Math.random() * enumValues.length);
return enumValues[index];
}
Solution 3:[3]
This is the best I could come up with, but it looks like a hack and depends on the implementation of enum in TypeScript, which I'm not sure is guaranteed to stay the same.
Given an enumeration such as
enum Color { Red, Green, Blue }
if we console.log it, we get the following output.
{
'0': 'Red',
'1': 'Green',
'2': 'Blue',
Red: 0,
Green: 1,
Blue: 2,
}
This means we can go through this object's keys and grab only numeric values, like this:
const enumValues = Object.keys(Color)
.map(n => Number.parseInt(n))
.filter(n => !Number.isNaN(n))
In our case, enumValues is now [0, 1, 2]. We now only have to pick one of these, at random. There's a good implementation of a function which returns a random integer between two values, which is exactly what we need to randomly select an index.
const randomIndex = getRandomInt(0, enumValues.length)
Now we just pick the random enumeration value:
const randomEnumValue = enumValues[randomIndex]
Solution 4:[4]
If you need to support string or heterogeneous enums, I might suggest a function like this:
const randomEnumKey = enumeration => {
const keys = Object.keys(enumeration)
.filter(k => !(Math.abs(Number.parseInt(k)) + 1));
const enumKey = keys[Math.floor(Math.random() * keys.length)];
return enumKey;
};
To get a random value:
const randomEnumValue = (enumeration) => enumeration[randomEnumKey(enumeration)];
Or simply:
MyEnum[randomEnumKey(MyEnum)]
Example:
Solution 5:[5]
In addition to @sarink answer.
import _ from 'lodash';
export function getRandomValueFromEnum<E>(enumeration: { [s: string]: E } | ArrayLike<E>): E {
return _.sample(Object.values(enumeration)) as E;
}
Solution 6:[6]
You can find below code to get things done.
enum Colors {
Red,
blue,
pink,
yellow,
Orange
}
function getRandomColor(): string {
// returns the length
const len = (Object.keys(Colors).length / 2) - 1;
// calculate random number
const item = (Math.floor(Math.random() * len) + 0);
return Colors[item];
}
Solution 7:[7]
EDIT: Fixed type issue.
Tidying up @ShailendraSingh's answer a bit, if the enum is defined as in the question, without any custom indexes, then this is a simple approach:
enum Color {
Red, Green, Blue
}
function getRandomColor(): Color {
var key = Math.floor(Math.random() * Object.keys(Color).length / 2);
return Color[key];
}
Note that the return type Color here (as requested in the question) is actually the enum index and not a color name.
Solution 8:[8]
So no answer did work for me, I end up doing like this:
having the following enum
export enum Jokenpo {
PAPER = 'PAPER',
ROCK = 'ROCK',
SCISSOR = 'SCISSOR',
}
to random select
const index= Math.floor(Math.random() * Object.keys(Jokenpo).length);
const value= Object.values(Jokenpo)[index];
return Jokenpo[value];
I'm just getting a random value from the enums and using it to convert to the real thing.
Solution 9:[9]
Here is a solution that worked for me in ES5:
function getRandomEnum<T extends object>(anEnum: T): T[keyof T] {
const enumValues = Object.keys(anEnum)
.filter(key => typeof anEnum[key as keyof typeof anEnum] === 'number')
.map(key => key);
const randomIndex = Math.floor(Math.random() * enumValues.length)
return anEnum[randomIndex as keyof T];
}
Solution 10:[10]
It is not perfect, but could try something like this..
function getRandomEnum(input: object): any {
const inputTransform: { [key: string]: string } = input as { [key: string]: string };
const keysToArray = Object.keys(inputTransform);
const valuesToArray = keysToArray.map(key => inputTransform[key]);
if (!isNaN(parseInt(keysToArray[0], 10))) {
const len = keysToArray.length;
while (keysToArray.length !== len / 2) {
keysToArray.shift();
valuesToArray.shift();
}
}
const randIndex = Math.floor(keysToArray.length * Math.random());
return valuesToArray[randIndex];
}
Tested with...
enum Names {
foo,
bar,
baz,
// foo = "fooZZZ",
// bar = "barZZZ",
// baz = "bazZZZ",
}
for (let i = 0; i < 10; i += 1) {
const result = getRandomEnum(Names);
if (result === Names.foo) console.log(`${result} is foo`);
else if (result === Names.bar) console.log(`${result} is bar`);
else if (result === Names.baz) console.log(`${result} is baz`);
}
Outputs...
0 is foo
0 is foo
2 is baz
0 is foo
2 is baz
2 is baz
1 is bar
1 is bar
2 is baz
1 is bar
or...
bazZZZ is baz
bazZZZ is baz
bazZZZ is baz
barZZZ is bar
bazZZZ is baz
barZZZ is bar
barZZZ is bar
fooZZZ is foo
barZZZ is bar
fooZZZ is foo
Solution 11:[11]
enum Colors {
Red, Green, Blue
}
const keys = Object.keys(Colors)
const real_keys = keys.slice(keys.length / 2,keys.length)
const random = real_keys[Math.floor(Math.random()*real_keys.length)]
console.log(random)
Tested on TypeScript 3.5.2 using ESNext. It's quite simple.
Bonus using namespace
enum Colors {
Red,
Green,
Blue,
}
namespace Colors {
// You need to minus the function inside your namespace
// That's why I had - 1
// Because instead of 0,1,2,red,green,blue = 6
// It will be 0,1,2,red,green,blue,Random = 7
export function Random(): any {
const length = ((Object.keys(Colors).length - 1) / 2)
return Colors[Math.floor(Math.random() * length / 2)]
}
}
console.log(Colors.Random())
Solution 12:[12]
Ease solution that works with all types of enums
function randomEnum<T extends Record<string, number | string>>(anEnum: T): T[keyof T] {
const enumValues = getEnumValues(anEnum);
const randomIndex = Math.floor(Math.random() * enumValues.length);
return enumValues[randomIndex];
}
Used lodash, but function can be rewritten without it
function getEnumValues<T extends Record<string, number | string>>(anEnum: T): Array<T[keyof T]> {
const enumClone = _.clone(anEnum);
_.forEach(enumClone, (_value: number | string, key: string) => {
if (!isNaN(Number(key))) {
delete enumClone[key];
}
});
return _.values(enumClone) as Array<T[keyof T]>;
}
enum Status { active, pending }
enum Type { active = 'active', pending = 'pending' }
enum Mixed { active = 'active', pending = 1 }
randomEnum(Status) // (Return random between 0,1)
randomEnum(Type) // (Return 'active' or 'pending' string)
randomEnum(Mixed) // (Return 'active' or 1)
Solution 13:[13]
this is working for me.
enum Colors {
Red = 'Red',
Green = 'Green',
Blue = 'Blue',
};
function getRandomInt(min: number, max: number) {
return Math.floor(Math.random() * max) + min;
}
const colorKeys = Object.keys(Colors) as (keyof typeof Colors)[];
const randomColor = Colors[
colorKeys[
getRandomInt(0, colorKeys.length)
]
];
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
