0

I want to add functions to an Enum type in my React Functional Components (i.e. classless) TypeScript project.

As already asked and answered here, this can be done in one of two ways:

class ModeUtil {
public static toString(mode: Mode) {
    return Mode[mode];
}

or

enum Mode {
    X,
    Y
}

namespace Mode {
    export function toString(mode: Mode): string {
        return Mode[mode];
    }

    export function parse(mode: string): Mode {
        return Mode[mode];
    }
}

Since I have been able to avoid classes in my project so far, I prefer keeping it that way and thus I'm in favor of the namespace approach.

However, the namespace approach is in violation with the no-namespace ESLint rule.

Hence, is use of classes a valid approach after all? I mean, in React, functional components were introduced in favor of class based components to avoid problems with mutation. In this context, the class itself would only contain static methods...

v3gard
  • 176
  • 2
  • 12
  • Enums are troublesome TS-only constructs, so if you need to use things that aren't desirable like namespaces or static-only classes, that"s the price. A more proper solution would be to ditch enums. – Estus Flask Sep 20 '21 at 13:19

2 Answers2

1

I don't think the React choice to move away from classes is something that means "In general, classes are bad and should be avoided". It just means "In React, a component can be better expressed and easily defined with a function component".

So answering to your question: classes ARE a valid approach in general. But it is up to you to understand if it fits your scenario. In your specific case, I think it can work smoothly. Or, if you think otherwise, you could just disable that eslint rule.

But, again, the fact that React dismissed class based components, doesn't mean that classes are bad. Just use React functional components and feel free to use classes whenever you think they could help.

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • Thanks. I know that classes in general are a valid approach, but I was more interested in the consensus of using classes in a React Functional Components project. If using a class in this context is considered accepted, the problem is solved. – v3gard Sep 20 '21 at 13:30
0

So I ended up with a module (i.e. non-class specific) approach without namespaces or module names. This ensures that I am compliant with the no-namespace ESLint rule, and I can keep my codebase clean without introducing classes.

Given that you have a Drink enum like this:

export enum Drink {
  GinTonic,
  LongIslandIceTea
}

You can then define your utils/helper functions like this:

import { Drink } from "../models/drink";

const toHumanString = (drink: Drink): string => {
  switch (drink) {
    case Drink.GinTonic:
      return "Gin Tonic";
    case Drink.LongIslandIceTea:
      return "Long Island Ice Tea";
    default:
      throw new Error(`Unknown drink ${drink}.`);
  }
};
const toMachineString = (drink: Drink) => {
  switch (drink) {
    case Drink.GinTonic:
      return "GinTonic";
    case Drink.LongIslandIceTea:
      return "LongIslandIceTea";
    default:
      throw new Error(`Unknown drink ${drink}.`);
  }
};
const parse = (drinkAsString: string): Drink => {
  switch (drinkAsString) {
    case "GinTonic":
      return Drink.GinTonic;
    case "LongIslandIceTea":
      return Drink.LongIslandIceTea;
    default:
      throw new Error(`Failed to parse drink ${drinkAsString}.`);
  }
};
export const DrinkUtils = {
  parse: parse,
  toHumanString: toHumanString,
  toMachineString: toMachineString
};

I added a demo here.

This works like a class with static methods, as the DrinkUtil object is available in the IDE at compile time.

IDE suggestions

v3gard
  • 176
  • 2
  • 12