Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum inside class (TypeScript definition file)

I've searched around but can't seem to find an answer for this, hopefully you can help.

How can I add an enum to Image? This is what I would like ideally but I get an error.

declare module 'Lib' {
  export module Graphics {
    export class Image {
      enum State {}

      static STATE_IDLE: State;
      static STATE_LOADING: State;
      static STATE_READY: State;
      static STATE_ERROR: State;
      constructor();
    }
  }
}

If I move State into the Graphics module it works but now State belongs to Graphics, which is incorrect. It needs to be part of Image.

like image 886
Lewis Peel Avatar asked Apr 24 '15 10:04

Lewis Peel


People also ask

Can we define enum inside a class TypeScript?

Enums or enumerations are a new data type supported in TypeScript. Most object-oriented languages like Java and C# use enums. This is now available in TypeScript too. In simple words, enums allow us to declare a set of named constants i.e. a collection of related values that can be numeric or string values.

Can you define an enum within a class?

Yes, we can define an enumeration inside a class. You can retrieve the values in an enumeration using the values() method.

Why are TypeScript enums bad?

The they are useless at runtime argument This is a false argument for typescript in general, let alone Enums. and agree, if at runtime some code tries to change the values of one of your enums, that would not throw an error and your app could start behaving unexpectedly ( that is why Object.

Should I use enum in TypeScript?

Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript. Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.


6 Answers

I think the following is an improvement on KoenT's solution:

export class Image
{
    constructor ()
    {
        this.state = Image.State.Idle;
    }

    state: Image.State;
}

export namespace Image
{
    export enum State
    {
        Idle,
        Loading,
        Ready,
        Error
    }
}

The advantage being that you can leverage named imports:

import {Image} from './image';
let img = new Image()
img.state = Image.State.Error
like image 172
NSjonas Avatar answered Oct 06 '22 06:10

NSjonas


Here's my solution.

program.ts:

enum Status {
    Deleting,
    Editing,
    Existing,
    New
}

export class Program {
    static readonly Status = Status;
    readonly Status = Program.Status;

    title: string;

    status: Status;

    constructor(init?: Partial<Program>) {
        Object.assign(this, init);
    }
}

Usage:

let program = new Program({ title: `some title` });

program.status = Program.Status.New;

or

program.status = program.Status.New;

Added benefit for Angular 2+ users: this can be used in templates

<div *ngIf="program.status === program.Status.New">
  Only display if status of the program is New
</div>
like image 23
Maz T Avatar answered Oct 06 '22 05:10

Maz T


I also bumped into this problem recently. This is what I am currently using as a solution:

// File: Image.ts

class Image
{
    constructor()
    {
        this.state = Image.State.Idle;
    }

    state: Image.State;
}

module Image
{
    export enum State
    {
        Idle,
        Loading,
        Ready,
        Error
    }
}

export = Image;

Then in the place where I'm using the class and its enum:

import Image = require("Image");

let state = Image.State.Idle;
let image = new Image();
state = image.state;

This seems to work fine (even though I don't consider it as the expected way to do this kind of thing).

Hopefully there will be a way in TypeScript to do it this way:

class Image
{
    enum State
    {
        Idle,
        Loading,
        Ready,
        Error
    }

    constructor()
    {
        this.state = State.Idle;
    }

    state: State;
}

export = Image;
like image 20
KoenT Avatar answered Oct 06 '22 07:10

KoenT


I think that this stuff with module augmentation is a very hacky and non-intuitive way* of doing things, so consider this:

export module Graphics
{
    enum State
    {
        STATE_IDLE,
        STATE_LOADING,
        STATE_READY,
        STATE_ERROR
    }

    export class Image
    {
        constructor() { }
        public static readonly State = State;
    }
}

//...

let imgState = Graphics.Image.State.STATE_ERROR;

That is, just declare the enum in the scope of the class that you want to add it to without exporting it, then expose it through a member of the class.

* Which in regards of structuring and organization of code is BAD, even if it technically works.

Update

declare module Lib
{
    enum State
    {
        STATE_IDLE,
        STATE_LOADING,
        STATE_READY,
        STATE_ERROR
    }

    class ImageClass
    {
        constructor();
        public Prop: any;
    }

    export interface Graphics
    {
        Image: typeof State & ImageClass & (new () => typeof State & ImageClass);
    }
}

declare var Graphics: Lib.Graphics;

Then you get typing like:

var someEnum = Graphics.Image.STATE_ERROR;
var image = new Graphics.Image();
var anotherEnum = image.STATE_IDLE;
like image 23
Alex Avatar answered Oct 06 '22 07:10

Alex


I think I may have found a solution...whether it's valid TypeScript I don't know but it works and doesn't cause any compile errors. It's a combination of the above answers.

declare module 'Lib' {

  module Graphics {

    module Image {
      enum State { }
      var STATE_IDLE: State;
      var STATE_LOADING: State;
      var STATE_READY: State;
      var STATE_ERROR: State;
    }

    class Image {
      constructor();
    }

  }

}

Can anyone spot any potential issues with this that I haven't noticed?

like image 42
Lewis Peel Avatar answered Oct 06 '22 06:10

Lewis Peel


I'm not sure what you intend to do, but I would have expected that you would want an enum to represent the possible state values, and then a state member on the image to indicate the current state of the image.

declare module 'Lib' {
    export module Graphics {

        enum State {
            STATE_IDLE,
            STATE_LOADING,
            STATE_READY,
            STATE_ERROR
        }

        export class Image {
            public state: State;

            constructor();
        }

    }
}

It sounds like you want to declare a class that has enum-like members, rather than declare an enum within a class. i.e:

declare module 'Lib' {

    export module Graphics {

        export class Image {
            static STATE_IDLE: number;
            static STATE_LOADING: number;
            static STATE_READY: number;
            static STATE_ERROR: number;

            constructor();
        }
    }
}
like image 42
Fenton Avatar answered Oct 06 '22 05:10

Fenton