143

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
3
  • note that if you declare new values to the same enum enum someEnum { c = 'string', b = someEnum.b } typescript will merge them together… but I would not recommend doing this as it will pollute the original enum Commented May 14, 2020 at 9:05
  • Unfortunately there's no way to do this as a enum i.e. have to use one of the type workarounds, and according to the TS Program Manager this is unlikely to change. See github.com/microsoft/TypeScript/issues/… Commented Jan 10, 2022 at 4:28
  • That solves a similar issue by using a utility function: stackoverflow.com/a/78825775/6996240 Commented Aug 2, 2024 at 13:59

4 Answers 4

106

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)

Sign up to request clarification or add additional context in comments.

4 Comments

Colors.Red does not work. Colors cannot be used like an enum, you get error ts2693: "'Colors' only refers to a type, but is being used as a value here."
this merges types, not an enum
I am surprised that Colors is defined as type and as a value, is that clean ? But @VictorP, regarding "you get error ts2693...": It works without an error for me.
Similar to @kca, I seem to be able to achieve my goals without the type Colors = Color1 | Color2; line.
53

I've just stumbled across this post from 2018 that explains how to do it with string based enums (see the original comment).

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

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)

Comments

20

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.

1 Comment

Only works if you use the enum as a type, not as value.
18

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

3 Comments

Thanks for the simple solution! 👍 The enum declarations didn't work for us, but using const declarations simplified our code. Since we only need the string valuesn we don't even need the type declarations.
You are a total genius! thanks, works like a charm
It is worth noting that you can use the same name "Colors" for both the object and the type: typescriptlang.org/play/?#code/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.