Use input fields like variables - graphql

Here's the way I pass variables now:
mutation Test($a: Int, $b: Int, $c: Int, $d: Int) {
test(a: $a, b: $b, c: $c, d: $d) {
id
}
}
// Example
{
a: 1,
b: 2,
c: 3,
d: 4
}
I want to put these variables into an input:
// Example
{
first: {
a: 1,
b: 2
},
second: {
c: 3,
d: 4
}
}
// GraphQL
input TestInput {
first: First
second: Second
}
input First {
a: Int
b: Int
}
input Second {
c: Int
d: Int
}
// The code below doesn't work
mutation Test($input: TestInput) {
test(a: $input.first.a, b: $input.first.b, c: $input.second.c, d: $input.second.d) {
id
}
}
This approach will save me from creating mapping functions and VM/Models in my code.
Is it even possible?

GraphQL does not currently support accessing individual fields on variable values that are objects. To make this work, you need to change your test field to accept a single argument of the type TestInput:
type Mutation {
test(input: TestInput): SomeType
}
then you can do:
mutation Test($input: TestInput) {
test(input: $input) {
id
}
}

Related

Can I rewrite a key value while iterating a sync.Map using it's reciever function Range(func(key, value interface{}) bool {...})

I have the example below as the existing sync.Map (I know, they are iterfaces,this is just visualized) :
[1: "Hello", 2: "Good", 3: "Morning"]
Can I use the sync.Map's built in (reciever) Range function while iterating on it using to change the value of the keys based on certain conditions? Example:
sync.Map.Range(func(key, value interface {}) bool {
if key.(int) == 1 {
sync.Map.Store(1, "Sorry")
}
if key.(int) == 2 {
sync.Map.Store(2, "Not")
}
if key.(int) == 3 {
sync.Map.Store(3, "Interested")
}
})

How to get access to enum variant unnamed field?

I would like to print data of tuple enum without named fields.
A tuple is a general way of grouping together some number of other values with a variety of types into one compound type.
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel { id: String::from("nickel") };
println!("{} {:?} ", penny.0, penny);
println!("{:?}", nickel);
}
In this example, Nickel is a struct-like enum variant, whereas Penny is simply called an enum variant.
I get a compiler error:
error[E0609]: no field `0` on type `Coin`
For more information about this error, try `rustc --explain E0609`.
You can use a match statement or alternatively an if let statement to use the variant's associated value:
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel {
id: String::from("nickel"),
};
if let Coin::Penny(name) = penny {
println!("{}", name);
}
if let Coin::Nickel{ id } = nickel {
println!("{}", id);
}
}
Playground link
Example using match statement:
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel {
id: String::from("nickel"),
};
match &penny {
Coin::Penny(id) => {
println!("{}; {:?}", id, penny);
}
_ => {}
}
match &nickel {
Coin::Nickel { id } => {
println!("{}; {:?}", id, nickel);
}
_ => {}
}
}
Playground link

Why do I get an error when pattern matching a struct-like enum variant with fields?

I can't get rid of an error on this code:
#[derive(PartialEq, Copy, Clone)]
pub enum OperationMode {
ECB,
CBC { iv: [u8; 16] },
}
pub struct AES {
key: Vec<u8>,
nr: u8,
mode: OperationMode,
}
impl AES {
pub fn decrypt(&mut self, input: &Vec<u8>) {
match self.mode {
OperationMode::ECB => {},
OperationMode::CBC(_) => {},
};
}
}
The pattern matching at the end of the decrypt function gives an error:
error[E0532]: expected tuple struct/variant, found struct variant `OperationMode::CBC`
--> src/main.rs:17:13
|
17 | OperationMode::CBC(_) => {},
| ^^^^^^^^^^^^^^^^^^ did you mean `OperationMode::CBC { /* fields */ }`?
It tells me to look at the output of rustc --explain E0532 for help, which I did.
They show this example of wrong code:
enum State {
Succeeded,
Failed(String),
}
fn print_on_failure(state: &State) {
match *state {
// error: expected unit struct/variant or constant, found tuple
// variant `State::Failed`
State::Failed => println!("Failed"),
_ => ()
}
}
In this example, the error occurs because State::Failed has a field which isn't matched. It should be State::Failed(ref msg).
In my case I'm matching the field of my enum because I'm doing OperationMode::CBC(_). Why does the error happen?
Enum variants have three possible syntaxes:
unit
enum A { One }
tuple
enum B { Two(u8, bool) }
struct
enum C { Three { a: f64, b: String } }
You have to use the same syntax when pattern matching as the syntax the variant was defined as:
unit
match something {
A::One => { /* Do something */ }
}
tuple
match something {
B::Two(x, y) => { /* Do something */ }
}
struct
match something {
C::Three { a: another_name, b } => { /* Do something */ }
}
Beyond that, you can use various patterns that allow ignoring a value, such as _ or ... In this case, you need curly braces and the .. catch-all:
OperationMode::CBC { .. } => { /* Do something */ }
See also:
Ignoring Values in a Pattern in The Rust Programming Language
Appendix B: Operators and Symbols in The Rust Programming Language
How to match struct fields in Rust?

Typescript: Declare function that takes parameter of exact interface type, and not one of its derived types

interface I {
a: number;
}
interface II extends I {
b: number;
}
function f(arg: I) : void {
// do something with arg without trimming the extra properties (logical error)
console.log(arg);
}
const obj: II = { a:4, b:3 };
f(obj);
What I want to do is to make function f to accept only objects of type I and not type II or any other derived interface
Difficult because of the way typescript works. What you can do is add a type field to the base, which a derived interface would override. Then to limit a function to only accept the base explicitly:
interface IFoo<T extends string = "foo"> {
type: T;
}
interface IBar extends IFoo<"bar"> {
}
function ray(baseOnly: IFoo<"foo">) {
}
let foo: IFoo = { type: "foo" };
let bar: IBar = { type: "bar" };
ray(foo); // OK!
ray(bar); // error
and the output error:
[ts]
Argument of type 'IBar' is not assignable to parameter of type 'IFoo<"foo">'.
Types of property 'type' are incompatible.
Type '"bar"' is not assignable to type '"foo"'.
You cannot achieve this in Typescript, in general, in most languages you cannot make such a constraint. One principle of object oriented programming is that you can pass a derived class where a base class is expected. You can perform a runtime check and if you find members that you don't expect, you can throw an error. But the compiler will not help you achieve this.
This works for me (on ts 3.3 anyway):
// Checks that B is a subset of A (no extra properties)
type Subset<A extends {}, B extends {}> = {
[P in keyof B]: P extends keyof A ? (B[P] extends A[P] | undefined ? A[P] : never) : never;
}
// Type for function arguments
type Strict<A extends {}, B extends {}> = Subset<A, B> & Subset<B, A>;
// E.g.
type BaseOptions = { a: string, b: number }
const strict = <T extends Strict<BaseOptions, T>>(options: T) => { }
strict({ a: "hi", b: 4 }) //Fine
strict({ a: 5, b: 4 }) //Error
strict({ a: "o", b: "hello" }) //Error
strict({ a: "o" }) //Error
strict({ b: 4 }) //Error
strict({ a: "o", b: 4, c: 5 }) //Error
// Type for variable declarations
type Exact<A extends {}> = Subset<A, A>;
// E.g.
const options0: Exact<BaseOptions> = { a: "hi", b: 4 } //Fine
const options1: Exact<BaseOptions> = { a: 5, b: 4 } //Error
const options2: Exact<BaseOptions> = { a: "o", b: "hello" } //Error
const options3: Exact<BaseOptions> = { a: "o" } //Error
const options4: Exact<BaseOptions> = { b: 4 } //Error
const options5: Exact<BaseOptions> = { a: "o", b: 4, c: 5 } //Error
// Beware of using Exact for arguments:
// For inline arguments it seems to work correctly:
exact({ a: "o", b: 4, c: 5 }) //Error
strict({ a: "o", b: 4, c: 5 }) //Error
// But it doesn't work for arguments coming from variables:
const options6 = { a: "o", b: 4, c: 5 }
exact(options6) // Fine -- Should be error
strict(options6) //Error -- Is correctly error
You can see more detail in my comment here.
So applied to your example:
interface I { a: number; }
interface II extends I { b: number; }
function f<T extends Strict<I, T>>(arg: T): void {
// do something with arg without trimming the extra properties (logical error)
console.log(arg);
}
const obj1: I = { a: 4 };
const obj2: II = { a: 4, b: 3 };
f(obj1); // Fine
f(obj2); // Error
Another possibility is to give up on interfaces and use classes with private properties and private constructors. These discourage extension:
export class I {
private clazz: 'I'; // private field
private constructor(public a: number) {
Object.seal(this); // if you really don't want extra properties at runtime
}
public static make(a: number): I {
return new I(a); // can only call new inside the class
}
}
let i = I.make(3);
f(i); // okay
You can't create an I as an object literal:
i = { a: 2 }; // error, isn't an I
f({a: 2}); // error, isn't an I
You can't subclass it:
class II extends I { // error, I has a private constructor
b: number;
}
You can extend it via interface:
interface III extends I {
b: number;
}
declare let iii: III;
and you can call the function on the extended interface
f(iii);
but you still can't create one with an object literal
iii = { a: 1, b: 2 }; // error
or with destructuring (which creates a new object also),
iii = { ...I.make(1), b: 2 };
, so this is at least somewhat safer than using interfaces.
There are ways around this for crafty developers. You can get TypeScript to make a subclass via Object.assign(), but if you use Object.seal() in the constructor of I you can at least get an error at runtime:
iii = Object.assign(i, { b: 17 }); // no error at compile time, error at runtime
And you can always silence the type system with any, (although again, you can use an instanceof guard inside f() to cause an error at runtime).
iii = { a: 1, b: 2 } as any; // no error
f(iii); // no error at compile time, maybe error if f() uses instanceof
Hope that helps; good luck!

How to get names of enum entries?

I would like to iterate a TypeScript enum object and get each enumerated symbol name, for example:
enum myEnum { entry1, entry2 }
for (var entry in myEnum) {
// use entry's name here, e.g., "entry1"
}
Though the answer is already provided, Almost no one pointed to the docs
Here's a snippet
enum Enum {
A
}
let nameOfA = Enum[Enum.A]; // "A"
Keep in mind that string enum members do not get a reverse mapping generated at all.
The code you posted will work; it will print out all the members of the enum, including the values of the enum members. For example, the following code:
enum myEnum { bar, foo }
for (var enumMember in myEnum) {
console.log("enum member: ", enumMember);
}
Will print the following:
Enum member: 0
Enum member: 1
Enum member: bar
Enum member: foo
If you instead want only the member names, and not the values, you could do something like this:
for (var enumMember in myEnum) {
var isValueProperty = Number(enumMember) >= 0
if (isValueProperty) {
console.log("enum member: ", myEnum[enumMember]);
}
}
That will print out just the names:
Enum member: bar
Enum member: foo
Caveat: this slightly relies on an implementation detail: TypeScript compiles enums to a JS object with the enum values being members of the object. If TS decided to implement them different in the future, the above technique could break.
For me an easier, practical and direct way to understand what is going on, is that the following enumeration:
enum colors { red, green, blue };
Will be converted essentially to this:
var colors = { red: 0, green: 1, blue: 2,
[0]: "red", [1]: "green", [2]: "blue" }
Because of this, the following will be true:
colors.red === 0
colors[colors.red] === "red"
colors["red"] === 0
This creates a easy way to get the name of an enumerated as follows:
var color: colors = colors.red;
console.log("The color selected is " + colors[color]);
It also creates a nice way to convert a string to an enumerated value.
var colorName: string = "green";
var color: colors = colors.red;
if (colorName in colors) color = colors[colorName];
The two situations above are far more common situation, because usually you are far more interested in the name of a specific value and serializing values in a generic way.
If you only search for the names and iterate later use:
Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];
Assuming you stick to the rules and only produce enums with numeric values, you can use this code. This correctly handles the case where you have a name that is coincidentally a valid number
enum Color {
Red,
Green,
Blue,
"10" // wat
}
var names: string[] = [];
for(var n in Color) {
if(typeof Color[n] === 'number') names.push(n);
}
console.log(names); // ['Red', 'Green', 'Blue', '10']
It seems that none of the answers here will work with string-enums in strict-mode.
Consider enum as:
enum AnimalEnum {
dog = "dog", cat = "cat", mouse = "mouse"
}
Accessing this with AnimalEnum["dog"] may result in an error like:
Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof AnimalEnum'.ts(7053).
Proper solution for that case, write it as:
AnimalEnum["dog" as keyof typeof AnimalEnum]
With current TypeScript Version 1.8.9 I use typed Enums:
export enum Option {
OPTION1 = <any>'this is option 1',
OPTION2 = <any>'this is option 2'
}
with results in this Javascript object:
Option = {
"OPTION1": "this is option 1",
"OPTION2": "this is option 2",
"this is option 1": "OPTION1",
"this is option 2": "OPTION2"
}
so I have to query through keys and values and only return values:
let optionNames: Array<any> = [];
for (let enumValue in Option) {
let optionNameLength = optionNames.length;
if (optionNameLength === 0) {
this.optionNames.push([enumValue, Option[enumValue]]);
} else {
if (this.optionNames[optionNameLength - 1][1] !== enumValue) {
this.optionNames.push([enumValue, Option[enumValue]]);
}
}
}
And I receive the option keys in an Array:
optionNames = [ "OPTION1", "OPTION2" ];
As of TypeScript 2.4, enums can contain string intializers https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html
This allows you to write:
enum Order {
ONE = "First",
TWO = "Second"
}
console.log(`One is ${Order.ONE.toString()}`);
and get this output:
One is First
This solution work too.
enum ScreenType {
Edit = 1,
New = 2,
View = 4
}
var type: ScreenType = ScreenType.Edit;
console.log(ScreenType[type]); //Edit
In a nutshell
if your enums is as below:
export enum Colors1 {
Red = 1,
Green = 2,
Blue = 3
}
to get specific text and value:
console.log(Colors1.Red); // 1
console.log(Colors1[Colors1.Red]); // Red
to get list of value and text:
public getTextAndValues(e: { [s: number]: string }) {
for (const enumMember in e) {
if (parseInt(enumMember, 10) >= 0) {
console.log(e[enumMember]) // Value, such as 1,2,3
console.log(parseInt(enumMember, 10)) // Text, such as Red,Green,Blue
}
}
}
this.getTextAndValues(Colors1)
if your enums is as below:
export enum Colors2 {
Red = "Red",
Green = "Green",
Blue = "Blue"
}
to get specific text and value:
console.log(Colors2.Red); // Red
console.log(Colors2["Red"]); // Red
to get list of value and text:
public getTextAndValues(e: { [s: string]: string }) {
for (const enumMember in e) {
console.log(e[enumMember]);// Value, such as Red,Green,Blue
console.log(enumMember); // Text, such as Red,Green,Blue
}
}
this.getTextAndValues(Colors2)
Another interesting solution found here is using ES6 Map:
export enum Type {
low,
mid,
high
}
export const TypeLabel = new Map<number, string>([
[Type.low, 'Low Season'],
[Type.mid, 'Mid Season'],
[Type.high, 'High Season']
]);
USE
console.log(TypeLabel.get(Type.low)); // Low Season
TypeLabel.forEach((label, value) => {
console.log(label, value);
});
// Low Season 0
// Mid Season 1
// High Season 2
Let ts-enum-util (github, npm) do the work for you and provide a lot of additional type-safe utilities. Works with both string and numeric enums, properly ignoring the numeric index reverse lookup entries for numeric enums:
String enum:
import {$enum} from "ts-enum-util";
enum Option {
OPTION1 = 'this is option 1',
OPTION2 = 'this is option 2'
}
// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();
// type: Option[]
// value: ["this is option 1", "this is option 2"]
const values = $enum(Option).getValues();
Numeric enum:
enum Option {
OPTION1,
OPTION2
}
// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();
// type: Option[]
// value: [0, 1]
const values = $enum(Option).getValues();
In TypeScript, an enum is compiled to a map (to get the value from the key) in javascript:
enum MyEnum {
entry0,
entry1,
}
console.log(MyEnum['entry0']); // 0
console.log(MyEnum['entry1']); // 1
It also creates a reversed map (to get the key from the value):
console.log(MyEnum[0]); // 'entry0'
console.log(MyEnum[0]); // 'entry1'
So you can access the name of an entry by doing:
console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'
However, string enum has no reverse map by design (see comment and pull request) because this could lead to conflict between keys and values in the map object.
enum MyEnum {
entry0 = 'value0',
entry1 = 'value1',
}
console.log(MyEnum['value0']); // undefined
console.log(MyEnum['value1']); // undefined
If you want to force your string enum to compile a reversed map (you then have to make sure all the keys and values are different), you can use this trick:
enum MyEnum {
entry0 = <any>'value0',
entry1 = <any>'value1',
}
console.log(MyEnum['value0']); // 'entry0'
console.log(MyEnum['value1']); // 'entry1'
console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'
I got tired looking through incorrect answers, and did it myself.
THIS ONE HAS TESTS.
Works with all types of enumerations.
Correctly typed.
type EnumKeys<Enum> = Exclude<keyof Enum, number>
const enumObject = <Enum extends Record<string, number | string>>(e: Enum) => {
const copy = {...e} as { [K in EnumKeys<Enum>]: Enum[K] };
Object.values(e).forEach(value => typeof value === 'number' && delete copy[value]);
return copy;
};
const enumKeys = <Enum extends Record<string, number | string>>(e: Enum) => {
return Object.keys(enumObject(e)) as EnumKeys<Enum>[];
};
const enumValues = <Enum extends Record<string, number | string>>(e: Enum) => {
return [...new Set(Object.values(enumObject(e)))] as Enum[EnumKeys<Enum>][];
};
enum Test1 { A = "C", B = "D"}
enum Test2 { A, B }
enum Test3 { A = 0, B = "C" }
enum Test4 { A = "0", B = "C" }
enum Test5 { undefined = "A" }
enum Test6 { A = "undefined" }
enum Test7 { A, B = "A" }
enum Test8 { A = "A", B = "A" }
enum Test9 { A = "B", B = "A" }
console.log(enumObject(Test1)); // {A: "C", B: "D"}
console.log(enumObject(Test2)); // {A: 0, B: 1}
console.log(enumObject(Test3)); // {A: 0, B: "C"}
console.log(enumObject(Test4)); // {A: "0", B: "C"}
console.log(enumObject(Test5)); // {undefined: "A"}
console.log(enumObject(Test6)); // {A: "undefined"}
console.log(enumObject(Test7)); // {A: 0,B: "A"}
console.log(enumObject(Test8)); // {A: "A", B: "A"}
console.log(enumObject(Test9)); // {A: "B", B: "A"}
console.log(enumKeys(Test1)); // ["A", "B"]
console.log(enumKeys(Test2)); // ["A", "B"]
console.log(enumKeys(Test3)); // ["A", "B"]
console.log(enumKeys(Test4)); // ["A", "B"]
console.log(enumKeys(Test5)); // ["undefined"]
console.log(enumKeys(Test6)); // ["A"]
console.log(enumKeys(Test7)); // ["A", "B"]
console.log(enumKeys(Test8)); // ["A", "B"]
console.log(enumKeys(Test9)); // ["A", "B"]
console.log(enumValues(Test1)); // ["C", "D"]
console.log(enumValues(Test2)); // [0, 1]
console.log(enumValues(Test3)); // [0, "C"]
console.log(enumValues(Test4)); // ["0", "C"]
console.log(enumValues(Test5)); // ["A"]
console.log(enumValues(Test6)); // ["undefined"]
console.log(enumValues(Test7)); // [0, "A"]
console.log(enumValues(Test8)); // ["A"]
console.log(enumValues(Test9)); // ["B", "A"]
Online version.
Assume you have an enum
export enum SCROLL_LABEL_OFFSET {
SMALL = 48,
REGULAR = 60,
LARGE = 112
}
and you want to create a type based on enum but not just copy and paste.
You could use an enum to create your type like this:
export type ScrollLabelOffset = keyof typeof SCROLL_LABEL_OFFSET;
In result you will receive a type with possible values as 'SMALL' | 'REGULAR' | 'LARGE'
Starting from TypeScript 2.4, the enum would not contain the key as a member anymore. source from TypeScript readme
The caveat is that string-initialized enums can't be reverse-mapped to get the original enum member name. In other words, you can't write Colors["RED"] to get the string "Red".
My solution:
export const getColourKey = (value: string ) => {
let colourKey = '';
for (const key in ColourEnum) {
if (value === ColourEnum[key]) {
colourKey = key;
break;
}
}
return colourKey;
};
Based on some answers above I came up with this type-safe function signature:
export function getStringValuesFromEnum<T>(myEnum: T): (keyof T)[] {
return Object.keys(myEnum).filter(k => typeof (myEnum as any)[k] === 'number') as any;
}
Usage:
enum myEnum { entry1, entry2 };
const stringVals = getStringValuesFromEnum(myEnum);
the type of stringVals is 'entry1' | 'entry2'
See it in action
According to TypeScript documentation, we can do this via Enum with static functions.
Get Enum Name with static functions
enum myEnum {
entry1,
entry2
}
namespace myEnum {
export function GetmyEnumName(m: myEnum) {
return myEnum[m];
}
}
now we can call it like below
myEnum.GetmyEnumName(myEnum.entry1);
// result entry1
for reading more about Enum with static function follow the below link
https://basarat.gitbooks.io/typescript/docs/enums.html
I wrote an EnumUtil class which is making a type check by the enum value:
export class EnumUtils {
/**
* Returns the enum keys
* #param enumObj enum object
* #param enumType the enum type
*/
static getEnumKeys(enumObj: any, enumType: EnumType): any[] {
return EnumUtils.getEnumValues(enumObj, enumType).map(value => enumObj[value]);
}
/**
* Returns the enum values
* #param enumObj enum object
* #param enumType the enum type
*/
static getEnumValues(enumObj: any, enumType: EnumType): any[] {
return Object.keys(enumObj).filter(key => typeof enumObj[key] === enumType);
}
}
export enum EnumType {
Number = 'number',
String = 'string'
}
How to use it:
enum NumberValueEnum{
A= 0,
B= 1
}
enum StringValueEnum{
A= 'A',
B= 'B'
}
EnumUtils.getEnumKeys(NumberValueEnum, EnumType.Number);
EnumUtils.getEnumValues(NumberValueEnum, EnumType.Number);
EnumUtils.getEnumKeys(StringValueEnum, EnumType.String);
EnumUtils.getEnumValues(StringValueEnum, EnumType.String);
Result for NumberValueEnum keys: ["A", "B"]
Result for NumberValueEnum values: [0, 1]
Result for StringValueEnumkeys: ["A", "B"]
Result for StringValueEnumvalues: ["A", "B"]
They have provided a concept called 'reverse-mapping' in their official documentation. It helped me:
https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings
The solution is quite straight forward:
enum Enum {
A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
Having numeric enum:
enum MyNumericEnum {
First = 1,
Second = 2
}
You need to convert it to array first:
const values = Object.values(MyNumericEnum);
// ['First', 'Second', 1, 2]
As you see, it contains both keys and values. Keys go first.
After that, you can retrieve its keys:
values.slice(0, values.length / 2);
// ['First', 'Second']
And values:
values.slice(values.length / 2);
// [1, 2]
For string enums, you can use Object.keys(MyStringEnum) in order to get keys and Object.values(MyStringEnum) in order to get values respectively.
Though it's somewhat challenging to extract keys and values of mixed enum.
There are already a lot of answers here but I figure I'll throw my solution onto the stack anyway.
TypeScript Playground
enum AccountType {
Google = 'goo',
Facebook = 'boo',
Twitter = 'wit',
}
type Key = keyof typeof AccountType // "Google" | "Facebook" | "Twitter"
// this creates a POJO of the enum "reversed" using TypeScript's Record utility
const reversed = (Object.keys(AccountType) as Key[]).reduce((acc, key) => {
acc[AccountType[key]] = key
return acc
}, {} as Record<AccountType, string>)
For Clarity:
/*
* reversed == {
* "goo": "Google",
* "boo": "Facebook",
* "wit": "Twitter",
* }
* reversed[AccountType.Google] === "Google" 👍
*/
Reference for TypeScript Record
To iterate:
for (const [key, value] of Object.entries(reversed)) {
console.log(`${key}: ${value}`);
}
A nice helper function:
const getAccountTypeName = (type: AccountType) => {
return reversed[type]
};
// getAccountTypeName(AccountType.Twitter) === 'Twitter'
The only solution that works for me in all cases (even if values are strings) is the following :
var enumToString = function(enumType, enumValue) {
for (var enumMember in enumType) {
if (enumType[enumMember]==enumValue) return enumMember
}
}
You can use the enum-values package I wrote when I had the same problem:
Git: enum-values
var names = EnumValues.getNames(myEnum);
I found this question by searching "TypeScript iterate over enum keys". So I just want to post solution which works for me in my case. Maybe it'll help to someone too.
My case is the following: I want to iterate over each enum key, then filter some keys, then access some object which has keys as computed values from enum. So this is how I do it without having any TS error.
enum MyEnum = { ONE = 'ONE', TWO = 'TWO' }
const LABELS = {
[MyEnum.ONE]: 'Label one',
[MyEnum.TWO]: 'Label two'
}
// to declare type is important - otherwise TS complains on LABELS[type]
// also, if replace Object.values with Object.keys -
// - TS blames wrong types here: "string[] is not assignable to MyEnum[]"
const allKeys: Array<MyEnum> = Object.values(MyEnum)
const allowedKeys = allKeys.filter(
(type) => type !== MyEnum.ONE
)
const allowedLabels = allowedKeys.map((type) => ({
label: LABELS[type]
}))
You can get an array of names from Enum in this way:
const enumNames: string[] = Object.keys(YourEnum).filter(key => isNaN(Number(key)));
Old question, but, why do not use a const object map?
Instead of doing this:
enum Foo {
BAR = 60,
EVERYTHING_IS_TERRIBLE = 80
}
console.log(Object.keys(Foo))
// -> ["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE", 60, 80]
Do this (pay attention to the as const cast):
const Foo = {
BAR: 60,
EVERYTHING_IS_TERRIBLE: 80
} as const
console.log(Object.keys(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> [60, 80]
If you have enum
enum Diet {
KETO = "Ketogenic",
ATKINS = "Atkins",
PALEO = "Paleo",
DGAF = "Whatever"
}
Then you can get key and values like:
Object.keys(Diet).forEach((d: Diet) => {
console.log(d); // KETO
console.log(Diet[d]) // Ketogenic
});
I find that solution more elegant:
for (let val in myEnum ) {
if ( isNaN( parseInt( val )) )
console.log( val );
}
It displays:
bar
foo
To get the list of the enum values you have to use:
enum AnimalEnum {
DOG = "dog",
CAT = "cat",
MOUSE = "mouse"
}
Object.values(AnimalEnum);

Resources