Exploring the integration of namespace with enums in TypeScript

In the angular project I am currently working on, we are utilizing typescript for development.

One key aspect of our project is an enum that defines various statuses:

export enum Status {
  ACTIVE = 'ACTIVE',
  DEACTIVE = 'DEACTIVE'
}

The duplication of properties/fields within the enum serves a specific purpose related to serialization and deserialization. Without it, Status.ACTIVE would be represented as 0 in terms of ordinality.

For visualization purposes, we require a mapping of these status labels to more user-friendly words; for example, translating 'ACTIVE' to 'Active'.

To achieve this, we have implemented namespaces in the following way:

export namespace Status {
  export function displayName(s: Status){
    const mapping = {Status.ACTIVE: 'Active', ...}; 
    return mapping[s];
  }
}

This approach simplifies the usage of Status, allowing for both direct access to enums like Status.ACTIVE and using Status.displayName(s). This keeps the code organized within the same 'classname' concept defined in the status.ts file.

However, given that default linting rules suggest avoiding namespaces with messages like 'namespace' and 'module' are disallowed (no-namespace), some questions arise:

  1. Does the use of namespaces introduce any performance or optimization concerns?
  2. Is there a more efficient way to achieve the same functionality while maintaining the 'class' name consistency?
  3. Could exporting another function without a namespace within the same file serve as a viable solution? Although this may not fully meet the original requirement of having the same class name.

An alternative implementation could look like the following:

status.ts

export Status {
  ACTIVE = 'ACTIVE'
}
export function statusToDisplayName(s: Status){
  const map = {...};
  return map[s];
}

usage.ts
import {Status, statusToDisplayName} from 'some/path/status';
...
status = Status.ACTIVE;
statusToDisplay = statusToDisplayName(status);

Answer â„–1

Comparison: Namespaces vs ES modules

When it comes to Namespaces and ES modules, the general consensus is that ES modules are preferred over Namespaces as the latter has been deemed deprecated. While using Namespaces with ES modules doesn't necessarily lead to performance issues, it can introduce confusion.

Read more about this topic

Using ES Modules Like a Namespace

One way to achieve similar functionality is by treating an ES module as a namespace:

// Status.ts
export enum Status {
  ACTIVE = 'ACTIVE',
  DEACTIVE = 'DEACTIVE'
}

export function toDisplayName(s: Status){
  const map = {...};
  return map[s];
}
// some-other-module.ts
import * as StatusModule from './Status.ts'

const active = StatusModule.Status.ACTIVE;
const displayname = StatusModule.toDisplayName(active);

If you prefer having statuses and functions on the same level, consider the following approach:

// Status.ts
enum Status {
  ACTIVE = 'ACTIVE',
  DEACTIVE = 'DEACTIVE'
}

export const ACTIVE = Status.ACTIVE;
export const DEACTIVE = Status.DEACTIVE;
export function toDisplayName(...){...}

However, note that this might lead to code duplication.

An Alternative Approach

To maintain the desired structure, you could define a class with static properties:

// Status.ts
enum StatusName {
  ACTIVE = 'ACTIVE',
  DEACTIVE = 'DEACTIVE'
}

export abstract class Status {
  static readonly ACTIVE = StatusName.ACTIVE
  static readonly DEACTIVE = StatusName.DEACTIVE
  
  static toDisplayName(status: StatusName) {...}
}

This method allows for better autocompletion when importing Status, but may introduce unnecessary properties in IntelliSense.

P.S.

You might be able to optimize your toDisplayName function to reduce additional work when adding new statuses.

If you need status names to be capitalized, you can create a capitalize function in a helpers or utils file:

// helpers/capitalize.ts
export const capitalize = (str: string) => {
  const firstLetter = str.charAt(0).toLocaleUpperCase();
  const rest = str.slice(1).toLocaleLowerCase();

  return firstLetter.concat(rest);
}
// Status.ts
export const toDisplayName = (status: StatusName) => capitalize(status);

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

Unable to retrieve shared schema from a different schema.graphql file within the context of schema stitching

In my project, I have a user schema defined in a file named userSchema.graphql; id: String! userName: String! email: String! password: String! } In addition to the user schema, I also have separate schema files for login and register functionalit ...

"Creating a dynamic TreeList in Ignite UI by linking pairs of names and corresponding

I recently developed a drag and drop tree list inspired by the tutorial on IgniteUI website. The main tree list functions properly, but I encountered an issue with the child nodes displaying as undefined, as illustrated in the image below: This is my Type ...

Whenever I navigate to a new page in my NEXTJS project, it loads an excessive number of modules

I am currently working on a small Next.js project and facing an issue where the initial load time is excessively long. Whenever I click on a link to navigate to a page like home/product/[slug], it takes around 12 seconds to load due to compiling over 2000 ...

Typescript Declarations for OpenLayers version 6

The package @types/openlayers found at https://www.npmjs.com/package/@types/openlayers only provides type definitions for version 4.6 of OpenLayers. This is clearly stated in the top comment within the file index.d.ts. If types for OpenLayers 6 are not av ...

Retrieve JSON data from a 404 response using the Http.get() method

I am attempting to retrieve JSON from a 404 response, but I am only receiving the Response {_body: "{myJSON}", status: 404, ok: false, statusText: "Not Found", headers: Headers…} How can I access the object itself so that I can display it in my HTML u ...

Having difficulties testing the Angular HTTP interceptor with Karma and Jasmine

Testing an http interceptor has been quite the challenge for me. Despite having my token logged in the console and ensuring that the request URL matches, I still can't figure out why it's not working with the interceptor in place. Interestingly, ...

Limit function parameter types to object keys

Is it possible to constrain my function parameter to match the keys of an object? I want to achieve something similar to this: export const details = { x: { INFO_x: 'xxx' }, y: { I ...

Struggling to identify the error while utilizing Jasmine's throwError function

I am relatively new to using Jasmine and have been experimenting with the toThrowError() function. However, I can't seem to get my test to pass successfully. In one of my functions, I purposely throw an error: test.service.ts test(list:{}){ if ...

Is it possible to pass multiple parameters in Angular by utilizing the click() function?

Is there a method for passing parameters with click() in Angular? <a asp-action="CreateSales" (click)="CreateSales(productname='pa', price='16.5')">Some Text</a> I am still learning Angular and would appreciat ...

The Child/Parent arguments in Typescript methods cannot be assigned

Why is this not working in TypeScript? class Parent { id: string = '' } class Child extends Parent{ name: string = '' } const fails: (created: Parent) => void = (created: Child) => { return }; const failsToo: ({ create ...

Is your React conditional rendering malfunctioning due to state issues?

I am attempting to create a component that will only be displayed after clicking on a search button. Below is the current code that I have: Update After making some changes, I am now encountering this error: Error: ERROR in /home/holborn/Documents/Work ...

Troubleshooting the Issue with Angular Material Dialog Imports

Hey there, I'm trying to utilize the Angular Material dialog, but I'm encountering issues with the imports and I can't seem to figure out what's wrong. I have an Angular Material module where I imported MatDialog, and I made sure to i ...

The payload from the Axios POST request is failing to reach its destination endpoint

I have two Express servers up and running - a gateway and an authentication service. I am facing an issue where the payload I set in the body of a request from my gateway to the authentication server never seems to arrive, despite there being no apparent C ...

Alerting Users Before Navigating Away from an Angular Page

I am looking to implement a feature in my app that will display a warning message when attempting to close the tab, exit the page, or reload it. However, I am facing an issue where the warning message is displayed but the page still exits before I can resp ...

Ways to resolve issues related to null type checking in TypeScript

I am encountering an issue with a property that can be null in my code. Even though I check for the value not being null and being an array before adding a new value to it, the type checker still considers the value as potentially null. Can anyone shed lig ...

Guide to customizing CSS styles within a div element using TypeScript code in a Leaflet legend

I'm struggling to add a legend to my map using Angular 5 and typescript. I need help with setting CSS styles for the values (grades) that are displayed on the legend. Can someone guide me on where to put the styles? TS: createLegend() { let lege ...

Is it feasible to implement early-return typeguards in Typescript?

There are instances where I find myself needing to perform type checks on variables within a function before proceeding further. Personally, I try to minimize nesting in my code and often utilize early-return statements to keep the main functionality of a ...

The new mui v5 Dialog is having trouble accepting custom styled widths

I am facing an issue with my MUI v5 dialog where I cannot seem to set its width using the style() component. import { Dialog, DialogContent, DialogTitle, Paper, Typography, } from "@mui/material"; import { Close } from "@mui/icons- ...

When utilizing useRef and useCallback in React, the output is visible in the console log but does not appear on the page

When working with API data, it's important to remember that the extraction process is asynchronous and the state may not be available at certain times. To handle this situation, we can utilize useCallback. However, even after successfully logging the ...

I am facing an issue with updating the mat-table after pushing values to a

I have a uniqueFormGroup with UniqueFormArray and a special-table that displays the array. When I add new uniqueFormGroup to UniqueFormArray, the special-table doesn't add new row. I was attempting to implement trackBy, but I am unsure of where (and ...