2

I have a typescript enum MyEnum:

export enum MyEnum {
  ALPHA = 'ALPHA',
  BETA = 'BETA'
}

I want to use the enum values as properties of another class. I know can do stuff like that:

export class MyClass {
  vals: {[key in MyEnum]} = {
    ALPHA: true,
    BETA: false
  }

  anotherProp: boolean;
  
  aMethod() {
    if (this.vals.ALPHA) doStuff();
  }
}

But I'm wondering if it's possible to use the enum values as properties of the class itself, not as properties of one of its nested objects:

export class myClass {
  // here be my properties from myEnum. How?

  anotherProp: boolean
  
  aMethod() {
    if (this.ALPHA) doStuff(); // ALPHA is type checked
  }
}

Is that possible?

2
  • Yes, you can add properties to your class where the property names are the enum values, and TypeScript can type-check them. There are a few ways to approach this depending on how “typed” you want the class to be. Commented May 23 at 10:08
  • for some reason i cannot comment my answer, added a link to the docs Commented May 23 at 12:33

3 Answers 3

2

You can merge an interface into the class:

https://www.typescriptlang.org/docs/handbook/declaration-merging.html

I use this pattern a lot:

Playground

enum MyEnum {
  ALPHA = 'ALPHA',
  BETA = 'BETA'
}

type BoolFlags = {[key in MyEnum]: boolean};
interface MyClass extends BoolFlags {};
class MyClass {
  
  constructor(){
    for(const key in MyEnum){
      this[(MyEnum as any)[key] as MyEnum] = false; // this could be done better, but not related to the question
    }
  }

  log() {
    if (this.ALPHA) console.log('ALPHA is', this.ALPHA);
  }
}

const a = new MyClass;
console.log(a.ALPHA, a.BETA);
a.ALPHA = true;
a.log();
Sign up to request clarification or add additional context in comments.

1 Comment

That seems to be the best answer, as it doesn't requires defining the properties, and thus doesn't require modification in the class if the enum changes. The syntax of defining both an interface and class with the same name is weird though, I'll read up on that. Thanks
2

If you want to avoid manual declaration and ensure that the class is always in sync with the enum, you can use a mapped type as a mixin or interface, then assign properties in the constructor or via Object.assign Enums, Mapped types

export enum MyEnum {
  ALPHA = 'ALPHA',
  BETA = 'BETA'
}

type EnumProps = {
  [K in MyEnum]: boolean
};

function doStuff() {}

export class MyClass implements EnumProps {
  [MyEnum.ALPHA]: boolean;
  [MyEnum.BETA]: boolean;
  anotherProp: boolean;

  constructor() {
    this.ALPHA = true;
    this.BETA = false;
    this.anotherProp = true;
  }

  aMethod() {
    if (this.ALPHA) doStuff();
  }
}

const obj = new MyClass();
obj.ALPHA;
obj.BETA;
obj.aMethod();

1 Comment

That works. I tried that with extends instead, and didn't think of implements. It requires to redefine all the props in the class though, which requires updating the class if the enum changes, but it does the job at implementing the type safety I wanted. Thanks
1

You can do something like this:

export enum MyEnum {
  ALPHA = 'ALPHA',
  BETA = 'BETA'
}

export class MyClass implements Record<MyEnum, boolean> {
  [MyEnum.ALPHA]: boolean;
  [MyEnum.BETA]: boolean;

  anotherProp: boolean;

  constructor(alpha: boolean, beta: boolean, anotherProp: boolean) {
    this[MyEnum.ALPHA] = alpha;
    this[MyEnum.BETA] = beta;
    this.anotherProp = anotherProp;
  }

  myMethod() {
    if (this[MyEnum.ALPHA]) {
      // todo: 
    }
  }
}

// You can create class with just
export class MyClass2 {
  [MyEnum.ALPHA]: boolean;
}

The only downside is slightly inconvenient syntax to access class properties:

  • in class instance methods: this[MyEnum.ALPHA]
  • in outer scope: instance[MyEnum.ALPHA]

Playground link

implements Record<MyEnum, boolean> enforce you to implement all enum values in your class as properties, you can skip it if you don't need all.

4 Comments

If you add/remove values from MyEnum, You must manually update the class. If you want to avoid manual declaration and ensure that the class is always in sync with the enum, you can use a mapped type as a mixin or interface, then assign properties in the constructor or via Object.assign
Makes sense. My guess @elcye wanted to see the syntax, how to declare and access class propreties defined as enum values
Makes sense in that case :)
It does the job the same as Omprakash S solution, with a different syntax in the extends. Although the downside mentioned isn't true from my tests: I can do this.ALPHA to access the attribute. And can declare the property as just ALPHA: boolean too. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.