2

Can ESLint be configured to flag the declaration of a string enum? E.g.:

enum Foo {
  Bar = "bar",
  Baz = "baz",
}

This is different from the no-mixed-enums rule. I have looked into no-restricted-syntax, but that doesn't cover @typescript-eslint rules as far as I know.

Some context:

  • Enums, particularly string enums are often considered anti-patterns, as is succinctly elaborated in this Stack Overflow post.
  • For now I would like to allow plain (unassigned integer) enums, so I wouldn't want to lint against the keyword itself.
  • Any linter config that flags any assignation of enum values would also work.

Eventually I would want all string enum declarations to be auto-fixable by a string union type, i.e.:

type Foo = "bar" | "baz";

Is there perhaps a plugin that can help with any of this?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
cneuro
  • 968
  • 13
  • 17

2 Answers2

1

In the simplest form you can use no-restricted-syntax:

{
  "rules": {
    "no-restricted-syntax": [
      "warn",
      {
        "selector": "TSEnumDeclaration",
        "message": "Verify enums don't contain StringLiteral values"
      }
    ]
  }
}

It's much more complex to write a linter rule for specific types as evidenced by typescript-eslint/no-mixed-enums. My advice would be to start with evaluating that code if you want a specific ruleset that will disallow only StringLiteral values.

anothermh
  • 9,815
  • 3
  • 33
  • 52
  • Thanks! I didn't know about ESTree node types like `TSEnumDeclaration`. Not sure about having an unfixable ESLint warning for a potentially legit `enum` though. Would you know of a selector that could parse at least any redeclaration of enum members? Perhaps you are right just ban enums altogether, as also several sources about best practices suggest. – cneuro Apr 18 '23 at 16:58
  • 1
    I do not. Use https://astexplorer.net/ to attempt to figure out the syntax. (set language to JavaScript and parser to @typescript-eslint/parser or typescript) You can also try https://ts-ast-viewer.com/. Beware: the AST syntax used by eslint is [gnarly](https://stackoverflow.com/a/75974135/3784008). And personally, I'd just ban enums entirely. – anothermh Apr 18 '23 at 17:05
1

As suggested by @anothermh, drilling down into the AST of an enum with @typescript-eslint/parser reveals which nodes to use in the selector. Link to gist.

The following rule works as intended:

{
  "rules": {
    "no-restricted-syntax": [
      "error",
      {
        "selector": "TSEnumDeclaration > TSEnumMember > Literal",
        "message": "Use a string union type instead."
      }
    ]
  }
}

When linting, it will flag only the literal of a declaration with the defined message.

E.g.:

enum test1 {
  member11,
  member12 = "test12",
}

enum test2 {
  member21 = "test21",
  member22 = "test22",
}

enum test3 {
  member31 = 31,
  member32,
}

enum test4 {
  member41,
  member42,
}

This is sufficient for my purposes currently. Then there are ways to automate the fixing of these errors by replacing the entire expression (for another time).

cneuro
  • 968
  • 13
  • 17
  • 1
    This is great. Did you find some resource to explain the syntax for `selector`? I've seen several different styles used and translating from AST Explorer to any given syntax hasn't been clear to me. Or if you have examples that you looked at to help you translate the AST to eslint-compatible syntax that would be great. – anothermh Apr 27 '23 at 17:04