Almost every time I want to use an enum in Typescript with MST I go down a rabbit hole reading https://www.typescriptlang.org/docs/handbook/enums.html So just for reference here are my notes from my most recent investigation:
export const DotPlotMode_CONTINUAL = "continual";
export const DotPlotMode_EACH_DOT = "each-dot";
export const DotPlotModeValues = [DotPlotMode_CONTINUAL, DotPlotMode_EACH_DOT] as const;
export type DotPlotMode = typeof DotPlotModeValues[number];
export const isDotPlotMode = (value: unknown): value is DotPlotMode => {
return DotPlotModeValues.includes(value as DotPlotMode);
};
The downsides are:
- you need to repeat
DotPlotMode_CONTINUAL - the container of the strings is not used when referencing them, so you can't run a single reference search to find all of the places using any of the strings.
There are two options for solving these two problems.
export enum DotPlotMode {
CONTINUAL = "continual",
EACH_DOT = "each-dot"
}
export const DotPlotModeValues = Object.values(DotPlotMode);
export const isDotPlotMode = (value: unknown): value is DotPlotMode => {
return DotPlotModeValues.includes(value as DotPlotMode);
};
export const DotPlotMode = {
CONTINUAL: "continual",
EACH_DOT: "each-dot"
} as const;
export type DotPlotMode = typeof DotPlotMode[keyof typeof DotPlotMode];
export const DotPlotModeValues = Object.values(DotPlotMode);
export const isDotPlotMode = (value: unknown): value is DotPlotMode => {
return DotPlotModeValues.includes(value as DotPlotMode);
};
The main difference is the need for the extra export type... when not a real enum.
Note: I'm not so sure about the duplicate definition of DotPlotMode in the non-enum case (one is an object one is a type). It seems to work, but perhaps will be confusing, or cause problems with linting rules. So you can also give one of them a different name perhaps EDotPlotMode.
A current benefit to not using the typescript enum keyword is that that the code will work in node.js v22 directly. node.js v22 supports basic type stripping out of the box. The enum keyword requires transformation not just stripping. However node.js does have an option --experimental-transform-types which will handle enums.
If you avoid const enum, all enums can be shared with other projects: published as types.
The reason to use an enum or object, is to make it easier to refactor the code and search for references. If you use a simple string union instead, then you'll probably want to define constants for each string. This requires more code, and it you can't search for all places that are using this set of strings with one VSCode reference query, instead you have to use multiple queries.