Reputation: 160
I want to convert a custom Typescript type into an enum. Here is my type:
export type TradeRequest {
status: 'trade',
id: ItemId,
slotNumber: number,
}
ItemId
itself is an enum. This is what it looks like:
export enum ItemId {
SHOVEL = 10000,
SWORD = 10001,
APPLE = 20000,
}
Here is the enum that I'm trying to create:
export enum TradeRequest {
STATUS = 'item',
ITEM_ID = ItemId,
SLOT_NUMBER = number,
}
When I do this, I get this error:
Only numeric enums can have computed members, but this expression has 'typeof ItemId' If you do not need exhaustiveness checks, consider using an object literal instead.
Upvotes: 0
Views: 5130
Reputation: 4183
You cannot compose enums with other enums. TypeScript enums are untagged. Therefore, they are simply values without context that you access by accessing the members with dot notation. You could try using a regular union like this:
export enum ItemId {
SHOVEL = 10000,
SWORD = 10001,
APPLE = 20000,
}
type TradeRequest = "item" | ItemId | number;
However, ItemId
's type is simply a union of the possible values - 10000 | 10001 | 20000
. Therefore, the number
type will eagerly consume it thus making the type compute to "item" | number
. I advise you use a C-Style union as I have described creating in this answer. Basically, you have a type object that looks like an enum but it's just an object and you create it via object literals and it forces you to only allow one member. This allows us to tag your data so that the ItemId
type is not consumed by number
type:
export enum ItemId {
SHOVEL = 10000,
SWORD = 10001,
APPLE = 20000,
}
// from https://stackoverflow.com/a/71476167/10873797
type CUnion<T extends Record<PropertyKey, unknown>>
= { [K in keyof T]: { [_ in K]: T[K] } & { [_ in Exclude<keyof T, K>]?: undefined } }[keyof T];
type TradeRequest = CUnion<{
status: 'trade',
id: ItemId,
slotNumber: number,
}>;
const foo1: TradeRequest = {
id: ItemId.APPLE
};
const foo2: TradeRequest = {
slotNumber: 2354,
};
const foo3: TradeRequest = {
status: "trade"
};
// then you access it like this
if (foo1.id !== undefined) {
// you know that it is the id variant
foo1.id // ItemId
foo1.slotNumber // undefined
foo1.status // undefined
}
Upvotes: 1