4

what is use of enum in typescript. If it's purpose is only to make code redable can't we just use constant for same purpose

enum Color {
Red = 1, Green = 2, Blue = 4
};


let obj1: Color = Color.Red;
obj1 = 100; // does not show any error in IDE while enum should accept some specific values

If there is no advantage of typechecking, Can't it be just written as.

const BasicColor = {
    Red: 1,
    Green: 2,
    Blue: 4
};

let obj2 = BasicColor.Red;
Daniel Rosenwasser
  • 21,855
  • 13
  • 48
  • 61
Nishant Baranwal
  • 1,048
  • 1
  • 10
  • 18
  • 2
    I can ask the same question back. What is the advantage of using constant object vs enum? With enum you at least see what kind of enum is expected by a function – smnbbrv Mar 08 '18 at 09:05
  • I'm wondering sort of the same, that's why we stopped using enums in our applications and switched them all to string literal values. They restrict you AND can be used for type checking as well - https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#string-literal-types – peter Mar 08 '18 at 09:09
  • [Should I use #define, enum or const?](https://stackoverflow.com/q/112433/995714), [Why use Enums instead of Constants?](https://stackoverflow.com/q/11575376/995714)... – phuclv Mar 08 '18 at 09:24

1 Answers1

7

First, in the following:

const BasicColor = {
    Red: 1,
    Green: 2,
    Blue: 4
};

Red, Green, and Blue are still mutable (whereas they are not in an enum).


Enums also provide a few things:

  1. a closed set of well known values (that won't permit typos later on), each which has...
  2. a respective set of literal-like types for each member, all which are provided...
  3. by a single named type which encompasses all values

To get that with something like a namespace, for example, you have to do something like

export namespace Color
    export const Red = 1
    export type Red = typeof Red;

    export const Green = 2;
    export type Green = 2;

    export const Blue = 3;
    export type Blue = typeof Blue;
}
export type Color = Color.Red | Color.Blue | Color.Green

What you're also noting is some unfortunate legacy behavior where TypeScript permits assignment from any numeric value to a numeric enum.

But if you're using a string enum, you won't get that behavior. There are also other things like exhaustiveness checking that you can enable with union enums:

enum E {
  Hello = "hello",
  Beautiful = "beautiful",
  World = "world"
}

// if a type has not been exhaustively tested,
// TypeScript will issue an error when passing
// that value into this function
function assertNever(x: never) {
  throw new Error("Unexpected value " + x);
}

declare var x: E;
switch (x) {
  case E.Hello:
  case E.Beautiful:
  case E.World:
    // do stuff...
    break;
  default: assertNever(x);
}
Daniel Rosenwasser
  • 21,855
  • 13
  • 48
  • 61
  • Thanks for the writeup. Do you have a source for "some unfortunate legacy behavior where TypeScript permits assignment from any numeric value to a numeric enum."? – Narretz Mar 09 '18 at 09:37
  • I explained this behavior in [an answer here](https://stackoverflow.com/a/49198352/2887218). @DanielRosenwasser, does the characterization of this as "unfortunate" mean you'd be amenable to a suggestion in GitHub to allow some notation for "strict/closed" versions of numeric enums? – jcalz Mar 09 '18 at 16:46
  • 2
    @jcalz maybe, but to be honest I don't think want to complicate things further with a flag or new construct. So feel free to do so, but I think we have reservations there. – Daniel Rosenwasser Mar 09 '18 at 17:10