How to get a random enum in TypeScript?
Olivia Zamora
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
} 16 Answers
After much inspiration from the other solutions, and the keyof keyword, here is a generic method that returns a typesafe random enum.
function randomEnum<T>(anEnum: T extends object): T[keyof T] { const enumValues = Object.keys(anEnum) .map(n => Number.parseInt(n)) .filter(n => !Number.isNaN(n)) as unknown as T[keyof T][] const randomIndex = Math.floor(Math.random() * enumValues.length) const randomEnumValue = enumValues[randomIndex] return randomEnumValue;
}Use it like this:
interface MyEnum {X, Y, Z}
const myRandomValue = randomEnum(MyEnum) myRandomValue will be of type MyEnum.
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))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];
} 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];
} 1 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.
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:
1This 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] 3 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.
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;
} 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];
} 3 If you are using the faker package (I use it for tests), you can use the following. This solution utilizes the arrayElement function to pick a random color from the Colors enum.
// Get an array of all values in the Colors enum
const colorValues = Object.values(Colors);
// Use arrayElement from faker to pick a random color from the array
const randomColor = faker.helpers.arrayElement(colorValues); 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];
} 3 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 baror...
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 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()) 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) A solution based on @Steven Spungin answer, and skipping the unnecessary filtering:
function randomEnum<T>(anEnum: T): T[keyof T] { const enumValues = Object.keys(anEnum) as T[keyof T][]; const randomIndex = Math.floor(Math.random() * enumValues.length / 2); return enumValues[randomIndex];
} 2 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) ]
]; 1