Simon Simon - 3 months ago 23
TypeScript Question

Don't know how to implement an enum using an interface in an angular2 class

Going around in circles here. Very new to Typescript and it's causing major headaches with trivial implementations.

How do a define in

AgentStatusService
that it should have an array of 4 options called
['offline','available','busy','away']
? AgentStatus is defined ( or is it? ) and I am injecting it into the
AgentStatusService
.

Microsoft Visual Studio Code is barfing on line 21 where the type 'typeof AgentStatus' is not assignable to type 'AgentStatus'... why?

Updated:

import { EventEmitter, Injectable } from '@angular/core';

export enum AgentStatus {
available =1 ,
busy = 2,
away = 3,
offline = 0
}

export interface IAgentStatusService {
state: number
states: AgentStatus
}
@Injectable()
export class AgentStatusService implements IAgentStatusService {

state:number; // this really should be string, but line 22 returns a number
states:AgentStatus;

constructor(states:typeof AgentStatus = AgentStatus){
// unreacheable code browser_adapter.ts:78EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property 'isSkipSelf' of null
// absolutely impossible to debug...
this.state = AgentStatus.offline // this returns a number
}

// set state(state:string){
// try{
// this._state = this.states[state];
// // string


// } catch(e){
// console.log('tried setting bad enum value on AgentStatus', e.stack);
// }
// }

// get state():string{
// return this._state;
// }

// get model():any {
// return this.states;
// }
}


Compare with
This implementation satisfies angular2:

@Injectable()
export class AgentStatusService {
public states = ['offline','available','busy','away'];
private _state;

constructor(){
this._state = this.states[0];
}

set state(state:string){
try{
this._state = this.states[state];
} catch(e){
console.log('tried setting bad enum value on AgentStatus', e.stack);
}
}

get state():string{
return this._state;
}

get model():any {
return this.states;
}
}

Answer

It's not obvious what you want here, but let me explain a few things...

I have created a blog post talking about this:
How to use TypeScript Enums, especially with Angular2
But I'll include all the information inline here:

A enum is just an object. Your enum is written something like this in JavaScript:

{
    0: "offline",
    1: "available",
    2: "busy",
    3: "away",
    available: 1,
    busy: 2,
    away: 3,
    offline: 0
}

The benefit from typing is very limited in enums.

This line is valid:

var value = <AgentStatus>"offline";

But it's not useful, because

value == AgentStatus.offline // <- false, because it's "offline" == 0

So, you should always store your values as numbers, which you can obtain as follows:

How to convert string to enum

var value = AgentStatus["offline"]; // so value is now 0

// You can also use this, which only gives IDE hints, no runtime benefit
var value: AgentStatus = AgentStatus["offline"];

This makes the previous comparison work:

value == AgentStatus.offline // <- true, because it's 0 == 0

Now, a couple questions remain:

How do you get the string equivalent?

AgentStatus.offline // 0
AgentStatus[AgentStatus.offline] // -> AgentStatus[0] -> "offline"

How do you get all possible enum values?

var options : string[] = Object.keys(AgentStatus);
// The options list has the numeric keys, followed by the string keys
// So, the first half is numeric, the 2nd half is strings
options = options.slice(options.length / 2);

Gotcha

If you write this in your template:

{{AgentStatus[myValue]}}

It will fail, because it doesn't have access to imported types (it gets executed later by AngularJS).

To make it work, your component will need to have a reference to the enum type / object, something like:

export class MyComponent {
    // allows you to use AgentStatus in template
    AgentStatus = AgentStatus;        

    myValue : AgentStatus;
    // ...
}

Runnable Demo

Here is an example that explains everything I pointed in here:

http://plnkr.co/edit/vOeeDrCI6CmsXdWaMtwG?p=preview

Look in the file: app/app.component.ts.

Comments