Skip to content

Instantly share code, notes, and snippets.

@scytacki
Last active November 3, 2025 15:14
Show Gist options
  • Select an option

  • Save scytacki/d94638a2275d3d7ceca5d186e623af0e to your computer and use it in GitHub Desktop.

Select an option

Save scytacki/d94638a2275d3d7ceca5d186e623af0e to your computer and use it in GitHub Desktop.
Notes on using enums in typescript, especially when using a runtime type system like MST.

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:

Avoiding the concept of enumerations entirely

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.

With enum

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);
};

Without enum

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);
};

Comparison

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.

Regarding other parts of the official enum documentation

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment