在打字稿中使用枚举的命名空间

working with namespace for enum in typescript

我正在做 angular 项目,所以我们在这里使用打字稿。

我有一个状态枚举

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

这里的 properties/fields 是重复的,因为它在 serialization/deserialization 中有帮助,如果没有 Status.ACTIVE 就变成 0 的顺序。

现在为了显示目的,我们需要映射可表达的词,比如, 'ACTIVE'-> 'Active'.

为此我们使用了命名空间,

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];
  }
}

这使得 Status 的使用变得非常简单。因为现在我可以拥有 Status.ACTIVE 以及 Status.displayName(s)。基本上使用相同的“classname”状态。 (当然两者都在 status.ts 文件中定义)

现在由于默认 lint 建议删除命名空间。

'namespace' and 'module' are disallowed (no-namespace)

我了解到命名空间是在 ES6 模块系统尚未到位时创建的。所以现在 classes 比名称空间更有意义。但就我而言 - 枚举的上下文

问题是,

  1. 命名空间的使用是否会产生任何性能、优化或任何其他问题?
  2. 有没有更好的方法来完成同样的事情(使用相同的“class”名称)
  3. 不创建命名空间并导出另一个以相同方式工作的函数 - 在同一个文件中运行但没有命名空间;那是解决方案吗?并且基本上不满足我最初要求具有相同 class 名称的要求。

喜欢关注

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);

命名空间与 ES 模块

命名空间被认为已弃用,取而代之的是 ES 模块。它不会导致任何性能或优化问题,但在与 ES 模块一起使用时肯定会造成一些混乱。

作为命名空间的 ES 模块

您可以使用 ES 模块作为命名空间来实现类似的结果

// 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);

如果您希望状态为 'on the same level' 且具有 toDisplayName 功能,您可以考虑以下选项

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

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

但我不推荐,因为会导致代码重复

备选

为了保持所需的结构,您可以尝试使用静态道具class声明一个

// 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) {...}
}

这样你在导入 Status 时会有很好的自动完成,但是会使用 IntelliSense 显示一些不必要的道具 Status.

P.S.

也许您的 toDisplayName 函数可以稍微优化一下,以防止在添加新状态时进行一些额外的工作

如果需要大写状态名,可以在helpers或者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);