Don't know how to implement an enum using an i

2019-04-06 19:49发布

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;    
    }
}

2条回答
我想做一个坏孩纸
2楼-- · 2019-04-06 20:22

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

You have states:AgentStatus = AgentStatus. Here states:AgentStatus is actually a value of type AgentStatus where as = AngentStatus is the whole enum.

Fix

you probably want:

states:typeof AgentStatus = AgentStatus

Or

states:AgentStatus = AgentStatus.Available

More

This is similar to you try to assign foo:SomeClass = SomeClass instead of foo:SomeClass = new SomeClass().

查看更多
不美不萌又怎样
3楼-- · 2019-04-06 20:27

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 Angular 2+
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 Angular).

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.

查看更多
登录 后发表回答