I am working on angular project so we are using typescript here.
I have an enum for statuses
export enum Status {
ACTIVE = 'ACTIVE',
DEACTIVE = 'DEACTIVE'
}
Here the properties/fields are duplicated because it helps in serialization/deserialization and without that Status.ACTIVE
becomes 0
for ordinality.
Now for display purposes, we need to have mapping of presentable words, like,
'ACTIVE'-> 'Active'
.
For this we used namespaces,
export namespace Status {
export function displayName(s: Status){
const mapping = {Status.ACTIVE: 'Active', ...}; // I know this can declared at some other places so we don't need to re-initialize every time this function is called.
return mapping[s];
}
}
This makes the usage of Status
very easy. Because now I can have Status.ACTIVE
as well as Status.displayName(s)
. Basically using same "classname" status. (of course both are defined in status.ts file)
Now since default lint suggest to remove namespaces.
'namespace' and 'module' are disallowed (no-namespace)
I understand that namespace was created when ES6 module system was not in place. So now classes make more sense than namespace. But in my case - enum's context
Questions are,
Like 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);
Namespaces are considered deprecated in favor of ES modules. It does not cause any performance or optimization issues, but definitely cause some confusion when used with ES modules.
You can use ES module as a namespace to achieve similar result
// 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 want statuses to be 'on the same level' with toDisplayName
function you can consider following option
// Status.ts
enum Status {
ACTIVE = 'ACTIVE',
DEACTIVE = 'DEACTIVE'
}
export const ACTIVE = Status.ACTIVE;
export const DEACTIVE = Status.DEACTIVE;
export function toDisplayName(...){...}
But I don't recommend it, because it will result in code duplication
To keep desired structure you can try to declare a class with static props
// 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 way you will have nice autocompletion when importing Status, but will have some unnecessary props showing up using IntelliSense for Status.
Maybe your toDisplayName
function can be a little bit optimized to prevent some additional work on adding new statuses
If you need a status name capitalized, you can declare capitalize function in helpers or utils
// 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);