枚举与常量

trn*_*rnj 30 typescript

as const使用over有什么优点和缺点enum?比如轻微的性能优势等。

enum Links {
    Link1 = 'test1',
    Link2 = 'test2',
}

const Links = {
    Link1: 'test1',
    Link2: 'test2',
} as const;
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 46

让我们将string enumsconst断言对象文字与字符串文字属性值进行比较!

概括:

  • 性能是一样的
  • anenum带来了命名值、命名类型和命名命名空间,如果您希望不使用 .an,则需要单独完成这些操作enum
  • 字符串enum是其名义子类型,string不能与其字符串文字值互换。

我们可以先放弃性能。几乎可以肯定,它们之间没有有意义的性能差异。两个版本在运行时的行为相同:您只有一个Links用这两个属性命名的对象。我也从未注意到编译器有什么不同;无论哪种方式都很快。如果性能确实是一个问题,那么您的enums 太大或者它们太多。


现在来看一些实际明显的差异。请注意,这种差异在一种情况下可能被视为优势,但在另一种情况下可能被视为劣势。这实际上取决于用例。因此,让我们看一下一个字符串enum,看看在不使用 的情况下我们可以多么接近它enum

enum Links {
    Link1 = 'test1',
    Link2 = 'test2',
}
Run Code Online (Sandbox Code Playgroud)

声明Links为 anenum将一些事情纳入范围:

  • 一个名为 的Links;运行时存在的对象,具有Links.Link1可分配给"test1"Links.Link2可分配给 的字符串值属性"test2"
  • 名为类型Links;对象的可能的并。作为一种类型,它仅在编译时存在。例如,您可以写为表示 a必须具有一个属性,该属性为或。Linksinterface Foo { link: Links }FoolinkLinks.Link1Links.Link2
  • 以名为和的导出类型命名的命名空间,它们分别对应于名为和 的值的类型。例如,您可以写为表示 a必须具有恰好为 的属性。这种事情对于建立歧视性工会来说是很方便的。LinksLinks.Link1Links.Link2Links.Link1Links.Link2interface Bar extends Foo { link: Links.Link1 }BarlinkLinks.Link1

您可以自己模拟其中的每一个enum,而无需声明 ,并获得在运行时和编译时的行为与字符串枚举非常相似(但不相同)的内容:

const Links = {
    Link1: 'test1',
    Link2: 'test2',
} as const;

type Links = (typeof Links)[keyof typeof Links];

namespace Links {
    export type Link1 = typeof Links.Link1;
    export type Link2 = typeof Links.Link2;
}
Run Code Online (Sandbox Code Playgroud)

因此,该enum语法的一个可能的优点是:如果您想用作Links值、类型和命名空间,这会自动发生;而要获得相同的效果而不enum需要大量的样板代码。另一方面,如果您不关心类型或名称空间,则可以编写const Links = {...}而不使这些不需要的东西存在。


如果上面的const+ type+namespace与 an 不同enum,有什么区别?

编译器将 anenum视为 的特殊名义子类型string。对于enum, 的类型Links.Link1可分配字符串文字“ ,但不能字符串文字“分配"test1”:

const to: "test1" = Links.Link1; // okay either way
const from: Links.Link1 = "test1"; // error for enum, okay for const
Run Code Online (Sandbox Code Playgroud)

因此,如果您想Links.Link1与字符串文字"完全互换"test1,那么您应该远离enum。另一方面,如果您想强制获取该"test1"值的唯一方法是写出Links.Link1,则应该使用enum.

这意味着字符串的理想用途enum是其中的值大部分被视为不透明的。如果 的用户enum实际上关心其特定的字符串文字值,则表明您可能并不真正想要enum. 例如,假设我将Links定义更改为:

enum Links {
    Link1 = '454353',
    Link2 = 'xxxyyyzzz',
}
Run Code Online (Sandbox Code Playgroud)

如果我的代码的其余部分对这一更改感到满意,那是因为我只通过索引到 来引用枚举值Links。任何直接提及的代码"test2"都会中断,但提及的代码Links.Links2将继续工作。


Playground 代码链接

  • 我们正在我的团队中进行这场辩论。我认为通常最好让枚举值_不_与字符串互换,以避免在字符串中出现拼写错误的风险。例如,如果函数返回一个包含 `{link: "testt2" as const}` 的对象,TypeScript 将不会说什么。当我尝试在需要“链接”的地方_使用_该值时,它会抱怨,但通常该错误会发生在远离实际发生拼写错误的位置,从而使拼写错误难以追查! (2认同)