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

I am experiencing issues with my HTML select list not functioning properly when utilizing a POST service

When using Angularjs to automatically populate a list with *ngFor and then implementing a POST service, the list stops functioning properly and only displays the default option. <select id="descripSel" (change)="selectDescrip()" > <option >S ...

Retrieving data from an API using VUEJS3 and Typescript

I am facing an issue with displaying data in my template. When I try to do so, the screen remains blank. I am using Vue.js 3 with TypeScript and I am fairly new to this technology. <template> <div> <img :src="datas[0].imag ...

TS fails to recognize any additional properties added to the constant object

When working on a function that should return an object with properties 'a' and 'b', I am defining the object first and then adding values to it later: const result = {}; result.a = 1; result.b = 2; return result; However, TypeScript i ...

In the desktop view, the onClick button requires two clicks to trigger the onClick function, while in the mobile view, it only takes one click as expected

Here are the topics I want to display as buttons: const paperTopics = [ "Teaching Aptitude", "Research Aptitude", "Comprehension", "Communication", "Mathematical Reasoning and Aptitude", ...

Introducing a delay in an observable causes incomplete data to be received in Angular using rxjs

Currently, I am facing an issue in my code where I am trying to introduce a delay using timer(500). However, the problem is that it is only returning partial data. Instead of the expected 17 fields, it is only returning 2 fields. Below is my code snippet f ...

Troubleshooting: Issues with APIGateway's Default Integration

I'm currently utilizing the AWS CDK to construct my API Gateway REST API My objective is to have my RestApi configured to automatically return an HTTP 404 error, so I set it up as follows: this.gateway = new apigw.RestApi(this, "Gateway", { ...

Error: The selected module is not a valid top-level option

I am facing an issue while using the babel-loader. I have removed all irrelevant code and just kept the error-related portion. What could be causing this problem? module.exports = merge(baseWebpackConfig, { ... module: { rules: [ ...

I'm confused why this particular method within a class is not being inherited by the next class. Rather than seeing the expected extension, I am presented with - [Function (

Working fine with the Person class, the register() function displays the correct return statement when logged in the console. However, upon extending it to the Employee class, instead of the expected return statement, the console logs show [Function (anon ...

Encountering a problem while attempting to host an Angular application on localhost:4200

After executing the ng serve command, I encountered an issue in the browser: An error occurred while trying to resolve "localhost:4200" ("") for "10.238.0.0": rpc error: code = Unknown desc = no such record I apologize if this question seems basic, as I ...

How to Decode JSON Data in Angular 2/4 with the Help of HttpClientModule

I am receiving this JSON structure from my asp.net core API: { "contentType": null, "serializerSettings": null, "statusCode": null, "value": { "productName": "Test", "shortDescription": "Test 123", "imageUri": "https://bla.com/bla", ...

What is the method to define a loosely typed object literal in a TypeScript declaration?

We are currently in the process of creating TypeScript definitions for a library called args-js, which is designed to parse query strings and provide the results in an object literal format. For example: ?name=miriam&age=26 This input will produce th ...

Set panning value back to default in Ionic

I need assistance with resetting the panning value. Essentially, I would like the panning value to return to 0 when it reaches -130. Below is my code snippet: swipeEvent($e) { if ($e.deltaX <= -130) { document.getElementById("button").click(); ...

The recursive component is functional exclusively outside of its own scope

I'm facing an issue where my recursive component is not nesting itself properly. The problem arises when I try to use the Recursive component inside another Recursive component. Although the root is correctly inserted into the Recursive component fro ...

angular2 ngif does not effectively conceal HTML elements when set to false

In the HTML file, I have the following code: <p *ngIf="!checklistsready"> not ready </p> <p *ngIf="checklistsready"> Ready </p> And in my TypeScript file, it looks like this: checklistsready: boolean = false; constructor( ...

Navigate Formik Fields on a Map

Material UI text-fields are being used and validated with Formik. I am looking for a way to map items to avoid repetitive typing, but encountering difficulties in doing so. return ( <div> <Formik initialValues={{ email: '&a ...

Whenever I try to import a function, I encounter the error message "no exported member."

I am facing an issue with my node/typescript application where I am attempting to import a function from another file. In order to export it, I utilized exports.coolFunc = coolFunc, and for importing, I used import {coolFunc} from '../controller/coolS ...

There is no overload that fits this call (regarding a basic array retrieved from an api)

While attempting to utilize a .map function on a simple array (['a','b','c']) fetched using the useEffect hook, I encountered an error in TypeScript. The array elements rendered correctly when the code was executed and no erro ...

Deleting an element from a two-field object in TypeScript 2

I am working with a 2-field object structure that looks like this { id: number, name: string } My goal is to remove the name field from this object. How can I achieve this in TypeScript? I have attempted using methods like filter and delete, but all I r ...

Issues arise when using Android BluetoothLeAdvertiser in Nativescript applications

I've been working on creating a Nativescript application that can send Bluetooth low energy advertisements. Since there are no existing Nativescript plugins for this functionality, I decided to develop a Java library (with plans to add a Swift library ...

What is the process for declaring a set in typescript?

In the documentation on basic types for Typescript, it explains using Arrays as a primitive type I am interested in the syntax: const numbers: string[] = [] How can I achieve the same with a set? ...