Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending Enum in typescript

I was hoping to reuse certain values in enum. Any suggestions of how to achieve such functionality.

enum someEnum {
    a = 'Some String',
    b = 2,
};

enum extendedEnum {
    c = 'string',
    b = someEnum.b
}

type someEnumType<T extends someEnum> = T extends someEnum.a ? string :
    T extends someEnum.b ? number : never;

type extendedEnumType<T extends extendedEnum> =
    T extends extendedEnum.c ? string:          // Gives Error
    T extends extendedEnum.b ? number : never;  // Gives Error
like image 891
Amol Gupta Avatar asked Oct 17 '18 14:10

Amol Gupta


People also ask

Can we extend enum?

No, we cannot extend an enum in Java. Java enums can extend java. lang. Enum class implicitly, so enum types cannot extend another class.

What is enum in TypeScript?

In TypeScript, enums, or enumerated types, are data structures of constant length that hold a set of constant values. Each of these constant values is known as a member of the enum. Enums are useful when setting properties or values that can only be a certain number of possible values.

Should enums be capitalized TypeScript?

Conventionally, the enum name and constant names are in Pascal case, where the first letter of each compound word is capitalized.

What is enum JavaScript?

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.


4 Answers

Currently, You can't extend enum in TypeScript

Another option is to use type:

enum Color1 {
    Red = "Red",
    Green = "Green"
}

enum Color2 {
    Yellow = "Yellow",
    Blue = "Blue"
}

define a new type named Colors :

type Colors = Color1 | Color2;

Then you can use it as below :

class AppComponent {
    public color: Colors;
    
    ngOnInit(): void {
      const Colors = { ...Color2, ...Color1 };
      this.color = Colors.Red; // Colors.Green or Colors.Yellow or Colors.Blue
    }
}

Stackblitz Here (Angular)

Stackblitz Here (Typescript)

like image 163
AbolfazlR Avatar answered Oct 20 '22 18:10

AbolfazlR


You could use a union in your type.

This works well for the task at hand. It allows to restrict x property to be only of values of abc or def enums. At the same time it allows using both enums as values.

enum abc {
    a = 1,
    b = 2,
    c = 3
}

enum def {
    d = 4,
    e = 5,
    f = 6
}

type abcdef = abc | def;

let x: abcdef;

x = abc.a;  // Here we use enum as value
x = def.d;  // As well here.

like image 35
William Moore Avatar answered Oct 20 '22 17:10

William Moore


I've just stumbled across this post from 2018 that explains how to do it with string based enums. See [1] for the original comment.

Here's an annotated / fruity version:

enum someEnum {
  Apple = 'Apple',
  Banana = 'Banana'
}

enum extendedEnum {
  Pear = 'Pear',
  Grape = 'Grape'
}

// The key seems to be to declare a type AND
// a const with the same name

type AllFruits = someEnum | extendedEnum;
const AllFruits = {...someEnum, ...extendedEnum};

let f: AllFruits = AllFruits.Grape;

The original poster (who, by all rights, seems to have been a contributor to TypeScript and knows what they're talking about) mentions that, using this method, you can't use something like AllFruits.Grape as a 'type literal', which means you can't do this:

// This error will appear: 
// 'AllFruits' only refers to a type, but is being used as a namespace here.

interface FruitBowl {
    fruit: AllFruits.Grape    
}

but this can be fixed with (something quite ugly) like:

interface FruitBowl {
    fruit: typeof AllFruits.Grape    
}

I guess this is one of the 'type workarounds' that others have mentioned.

(All credit to https://github.com/alangpierce) [1]: https://github.com/microsoft/TypeScript/issues/17592#issuecomment-449440944

like image 19
J Brewer Avatar answered Oct 20 '22 18:10

J Brewer


Union enum does not give type intellisense, but 'as const' object literal does.

const Color1 = {
    Red : "Red",
    Green : "Green"
} as const

const Color2 = {
    Yellow : "Yellow",
    Blue : "Blue"
} as const

const Colors = {...Color1, ...Color2} as const

type ValueOf<T> = T[keyof T];
type ColorsType = ValueOf<typeof Colors>

const c:ColorsType = Colors.Green  // use 'as const'

alert(c)

Try it here

like image 1
Eric Avatar answered Oct 20 '22 18:10

Eric