Enums in Typescript that are based on strings

After going through all the information on String Based Enums in Typescript, I have yet to find a solution that fits my specific needs. These are the requirements I am looking for:

  • Enums that offer code completion
  • Enums that can be looped over
  • No need to repeat elements
  • String-based enums

The enum possibilities I've come across in Typescript so far include:

  1. enum MyEnum {bla, blub}: This does not support string-based functionality, making it difficult to read from JSON files...
  2. type MyEnum = 'bla' | 'blub': Not iterable and lacks code completion
  3. Creating a custom
    class MyEnum { static get bla():string{return "bla"} ; static get blub():string{return "blub"}}
    : Involves specifying elements twice

Considering these limitations, I have the following questions:

  1. Is there currently no way to fulfill all of these requirements simultaneously? If not, will this be achievable in the future?
  2. Why weren't Enums designed to be string-based?
  3. Has anyone encountered similar issues and how did you resolve them?

Answer №1

In my opinion, there is nothing wrong with implementing an Enum in a C-like style with numbers. The whole point of an Enum (similar to a Symbol) is to declare a value that can be uniquely identified during development, regardless of how it is represented at runtime.

However, as developers, we sometimes desire to use the functionality of an Enum through an API that doesn't expose the actual enumeration values. Even if the API is essentially based on an Enum, restricting property values to just 'foo' and 'bar'.

Perhaps this is why some languages offer string-based Enums :)

The approach of TypeScript towards Enums

When you examine the transpiled JavaScript code, you'll notice that TypeScript simply utilizes a basic JavaScript Object for implementing an Enum. For instance:

enum Color {
    Red,
    Green,
    Blue
}

gets transpiled into:

{
  0: "Red",
  1: "Green",
  2: "Blue",
  Blue: 2,
  Green: 1,
  Red: 0
}

This allows you to access the string value like Color[Color.Red]. You still benefit from code completion without needing to specify the values twice. However, using Object.keys(Color) for iterating over the Enum would not work seamlessly due to the duplication of values within the object itself.

Answer №2

Why wasn't the decision made to use string-based enums?

To clarify, Enums in TypeScript can be utilized with both numbers and strings, where direct access is through number and reverse mapping via string (more information here).

Addressing your requirement

The main reason for abandoning raw enums is because

I am unable to directly read from JSONs that are string based...

You will encounter similar challenges when handling Dates since JSON lacks a date data type. To convert these, you would typically use new Date("someServerDateTime").

The same approach can be used to convert server-side enum (string) to TS enum (number), thanks to the reverse lookup MyEnum["someServerString"]

Data Transformation

This process of transforming server-side data into client-side active data is often referred to as Data Hydration. Currently, my preferred library for this task is https://github.com/pleerock/class-transformer

Personally, I manage this operation at the server access layer by creating an API that handles XHR requests and serialization tasks.

In my previous role, we automated this process using code generation tools that also supported common validation patterns between the server and client codebases.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A step-by-step guide on converting request.body to JSON in Django

Whenever I send a post request to my Django server using Postman or my Android app, the request.body is received in the format user=abc&pwd=123 instead of JSON. How can I parse this format into JSON using Python? ...

Manipulate the order of JSON data columns when using the Json() function in ASP.NET MVC

I have created a database table called Articles which contains the following columns: ID, Title, Excerpts, Content In my corresponding MVC model class: public class Articles { public int id { get; set; } public string Title { get; set; } pub ...

Python: Converting Unicode to a List of Dictionaries

I am looking to convert a JSON format into a table. The JSON format is currently in "unicode" instead of the desired "list of dict." Having it in "list of dict" would make it easier for me to create a table. import json import requests url = "http://local ...

Invalid action has been dispatched by the effect:

In my project, I am using Angular 7.1.4. This is an excerpt from my effect code: @Injectable() export class LoginEffects { constructor(private actions$: Actions, p ...

Getting JSON data with D3.js: A step-by-step guide

My JSON file is external and has a specific structure: { data: [ { 0: 'cat', 1: 232, 2: 45 }, { 0: 'dog', 1: 21, 2: 9 }, { 0: 'lion', ...

Retrieve the data exclusively when transferring information from Laravel to JSON

I am facing a challenge in my Laravel project where both the key and value are being passed to the variable I assigned when attempting to pass data in JSON format. I have tried using $data = json_encode($ip); inside the controller, but only one result is r ...

Using C# to deserialize JSON with Inheritance

Here is some code that creates an object, writes it to a file, reads from the file, and deserializes it back into the same object. The issue here is that when deserializing, the information in one of the properties is lost. internal class Program { pr ...

Error encountered when trying to convert a React Higher Order Component (HOC) to TypeScript: "Exported variable referencing private name"

Seeking assistance from TypeScript experts as I encounter an issue while attempting to convert a React Higher Order Component (HOC) into TS. I'm unsure of how to resolve this. "src/withEnv.tsx(15,14): error TS4025: Exported variable 'withE ...

The Discriminate Union is ineffective in handling function arguments

Trying to create a discriminate union type for two potential component props, but encountering issues with passing the argument to the onClick function in this instance: type TLink = { label: string, onClick?: (e: React.MouseEvent<HTMLAnchorElement& ...

Angular - Collaborative HTML format function

In my project, I have a function that sets the CSS class of an element dynamically. This function is used in different components where dynamic CSS needs to be applied. However, every time I make a change to the function, I have to update it in each compo ...

Tips for utilizing array filtering for parent and child elements in Angular 11

I am dealing with an array object and I need to apply certain conditions to fetch the data. this.knowledgeData = [ { "id": 3, "name": "Education", "isOtherCategory": 0, "isKno ...

What is the equivalent of a "Class" in Typescript for defining an "Interface"?

I am interested in passing "Interfaces" to a function. Not just a specific interface, but any interfaces. As explained here, for Class, I can handle it as a type. export type ClassType<T> = { new(...args: any[]): T }; function doSomethingWithAnyCla ...

A guide on integrating API data with EJS templates in a Node.js application

Having trouble with my index.js file located in the root directory const express = require("express"); const app = express(); const path = require("path"); const axios = require("axios").default; const cors = require("cors"); app.set("view engine", "ejs"); ...

Manipulating elements within nested JSON structures, including adding, updating, and deleting values

My current project involves developing a diagram/tree graph generator using two libraries: GraphView for generating the graph and ZoomLayout for view navigation. The goal of this project is to save JSON data in an AWS database and then display a list of al ...

Value that is constantly changing for ngModel

Is it possible to use a function as a value for ngModel in Angular? I need to be able to set the value for my input at a later point in time, so I want to check if the function exists before updating the model. However, the following code snippet is not ...

Do you need to redeclare the type when using an interface with useState in React?

Take a look at this snippet: IAppStateProps.ts: import {INoteProps} from "./INoteProps"; export interface IAppStateProps { notesData: INoteProps[]; } and then implement it here: useAppState.ts: import {INoteProps} from "./interfaces/INo ...

Utilizing next/image as a backgroundImage in a div container

Currently, I am working with nextjs and I am trying to set a background Image for a specific div using next/image. Most of the sources I found only explain how to implement full screen background images with next/image, not for a single div. I stumbled upo ...

Leveraging Ajax for transmitting JSON data and performing decoding operations

Previously, I used an AJAX script to fetch data from viewCommentsJson.php. The data retrieved looked like this: [{"comments":"Greta"},{"comments":"John"}]. Is there a way to decode and display this return value properly? Appreciate any assistance. Gret ...

"Exploring the world of Python API integration and dictionary

I have been struggling to figure out how to only print the word "devices" in my code, despite trying multiple methods. Can anyone provide guidance on how to achieve this? Additionally, I would like to know how to print the "model" of a single device or b ...

Adapt the selection sort method for sorting an array of strings based on their ascending length

I have an assignment for class that I am currently working on, but I am confused by the wording. The task is to modify the selection sort algorithm to sort an array of strings by increasing length. This assignment is from the book "Big C++ Late Objects ...