Enum inside class (TypeScript definition file)

TypescriptDefinition

Typescript Problem Overview


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.

Typescript Solutions


Solution 1 - Typescript

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

Solution 2 - Typescript

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>

Solution 3 - Typescript

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;

Solution 4 - Typescript

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;

Solution 5 - Typescript

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?

Solution 6 - Typescript

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

Solution 7 - Typescript

You could create a module and class with the same name. It might also help to rename your enum so that you don't have to say State twice:

declare module 'Lib' {
    export module Graphics {
    	export class Image {
    		constructor();
    	}
    
    	export module Image {
    		export enum State {
    			Idle,
    			Loading,
    			Ready,
    			Error
    		}
    	}
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLewis PeelView Question on Stackoverflow
Solution 1 - TypescriptNSjonasView Answer on Stackoverflow
Solution 2 - TypescriptMaz TView Answer on Stackoverflow
Solution 3 - TypescriptKoenTView Answer on Stackoverflow
Solution 4 - TypescriptAlexView Answer on Stackoverflow
Solution 5 - TypescriptLewis PeelView Answer on Stackoverflow
Solution 6 - TypescriptFentonView Answer on Stackoverflow
Solution 7 - TypescriptDavid SherretView Answer on Stackoverflow