Reputation: 2554
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
Upvotes: 130
Views: 142298
Reputation: 501
I've just stumbled across this post from 2018 that explains how to do it with string based enums (see 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)
Upvotes: 46
Reputation: 575
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
Upvotes: 15
Reputation: 3994
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.
Upvotes: 21
Reputation: 14842
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
}
}
Upvotes: 95