TS中字符串枚举和字符串文字类型之间的差异

jow*_*wey 42 typescript

假设我想确保myKey{ myKey: '' }只包含字符串foo,bar,baz,我可以通过两种方式实现这一目标.

   // with a String Literal Type 
   type MyKeyType = 'foo' | 'bar' | 'baz';

    // or with a String Enum   
    enum MyKeyType {
       FOO = 'foo',
       BAR = 'bar',
       BAZ = 'baz'
    }
Run Code Online (Sandbox Code Playgroud)

我想知道其中一个的利弊在哪里,因为两个看起来都是一样的(从我访问例如条件检查的值的方式来看).

我在TS文档中发现的唯一区别是Enums是运行时的真实对象,在某些情况下可能是可取的.

Rya*_*ugh 20

要理解的关键是字符串枚举的值是不透明的.

字符串枚举的预期用例是您不希望其他代码知道或关心文字字符串支持的MyKeyType.FOO内容.这意味着您将无法将文字字符串 "bar"传递给接受的函数MyKeyType- 您必须改为编写MyKeyType.BAR.

  • 所以你会说它们的行为方式没有真正的区别(它们都实现了相同的目标),但Enums提供了一些额外的抽象,可能在项目的后期阶段有用,例如重构? (3认同)

Dan*_*l R 10

嗯,在转译的代码中,字符串枚举和文字类型之间存在差异

比较打字稿代码

// with a String Literal Type 
type MyKeyType1 = 'foo' | 'bar' | 'baz';

// or with a String Enum   
enum MyKeyType2 {
   FOO = 'foo',
   BAR = 'bar',
   BAZ = 'baz'
}
Run Code Online (Sandbox Code Playgroud)

使用转译的JavaScript代码

// or with a String Enum   
var MyKeyType2;
(function (MyKeyType2) {
    MyKeyType2["FOO"] = "foo";
    MyKeyType2["BAR"] = "bar";
    MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
Run Code Online (Sandbox Code Playgroud)

您会看到的是,没有为字符串文字生成任何代码。因为Typescripts Transpiler仅在编译时用于类型安全。在运行时,字符串文字会“生成为哑”字符串。文字的定义和用法之间没有引用。

因此,存在第三种替代方法,称为const枚举

看这个

// with a String Literal Type 
type MyKeyType1 = 'foo' | 'bar' | 'baz';

// or with a String Enum   
enum MyKeyType2 {
   FOO = 'foo',
   BAR = 'bar',
   BAZ = 'baz'
}

// or with a Const String Enum   
const enum MyKeyType3 {
   FOO = 'foo',
   BAR = 'bar',
   BAZ = 'baz'
}

var a : MyKeyType1 = "bar" 
var b: MyKeyType2 = MyKeyType2.BAR
var c: MyKeyType3 = MyKeyType3.BAR
Run Code Online (Sandbox Code Playgroud)

将被转译为

// or with a String Enum   
var MyKeyType2;
(function (MyKeyType2) {
    MyKeyType2["FOO"] = "foo";
    MyKeyType2["BAR"] = "bar";
    MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
var a = "bar";
var b = MyKeyType2.BAR;
var c = "bar" /* BAR */;
Run Code Online (Sandbox Code Playgroud)

要进一步播放,您可以检查此链接

我更喜欢使用const枚举,因为键入Enum.Value的便捷方式。在编译时,Typescript会为我做剩下的事情,以获得最高的性能。

  • 关于 `const enum` 的一点说明:对于使用 Babel 转译 TS,从版本 7 开始,我们不能再使用 `const enum` 了。在他们修复它之前(https://github.com/babel/babel/issues/8741),您可能会看到您的项目在迁移到较新的构建系统时中断。请注意,babel7 相对于 babel6 的转译速度接近编译 TS 的两倍,因此大多数开发人员可能会推动这种迁移,并且必须将所有 const 枚举重构为枚举,在生产包中添加所有额外代码。 (3认同)
  • 感谢您提供的信息。我只是想指出,当使用 _const enum_ 时,您会失去 _numeric enums_ 或 _string enums_ 的一些功能(例如,您不能再循环它们)。如果您仍然尝试,TS 编译器会抱怨 _'const' 枚举只能在属性或索引访问表达式或导入声明或导出赋值或类型查询的右侧使用。通过您的示例,很明显为什么会出现这种情况。 (2认同)

Fra*_*ica 8

开发时枚举的一个好处是,您可以通过智能感知轻松看到选项列表:

在此处输入图片说明

同样,您可以使用重构工具轻松地更改枚举值,而不用在各处更改字符串。

编辑:在VS 2017和TypeScript> = 3.2.4中,intellisense使用字符串文字类型:

在此处输入图片说明

  • 好点,你在瑞安回答的评论中回答了我的问题,但他给了我更深入的理解 (3认同)

And*_*oni 6

枚举的一个很大的缺点是,如果您使用数字而不是字符串,那么在我看来,整个枚举并不安全:我总是可以将任何数字值分配给此类变量

enum TYPE {MAN = 1, WOMAN = 2, BOY = 3, GIRL = 4};
let foo: TYPE = TYPE.MAN;
foo = 37.14; //no problem for compiler
Run Code Online (Sandbox Code Playgroud)

  • 这个缺点似乎是故意的,以支持位标志 - [请参阅此处的答案](/sf/answers/4013429731/)。 (2认同)

yan*_*rab 5

使用枚举而不是字符串文字的好处之一是,您也可以在未声明类型的地方使用它。

例如 -

assert.equal(result.keyType, KeyType.FOO)
Run Code Online (Sandbox Code Playgroud)