TypeScript:为什么不强制使用确切的枚举类型?

Nur*_*yev 6 typescript

请看一下这个简单的代码:

const enum MyEnum {
    Zero
} 

const foo: MyEnum.Zero = 0 // OK as expected (since MyEnum.Zero is zero)
const bar: MyEnum.Zero = 1 // OK, but expected Error! Why?
Run Code Online (Sandbox Code Playgroud)

0在这种情况下,如何执行精确的窄数类型?

操场

UPD:枚举似乎已损坏https://github.com/microsoft/TypeScript/issues/11559

jca*_*alz 7

在当前 TypeScript 手册enum部分中并没有真正提到它,但是所有number值都可以分配给任何数字枚举类型。新的 TypeScript 手册的当前草稿如下

由于历史限制,一些[可分配性]规则很奇怪。例如,任何数字都可以分配给数字枚举,但这不适用于字符串枚举。只有已知是字符串枚举的一部分的字符串才能分配给它。那是因为数字枚举存在于联合类型和文字类型之前,所以它们的规则最初是宽松的。

似乎 TypeScript 中的数字枚举历来被用来支持位域,使用位掩码和按位操作来组合显式声明的枚举值以获得新的值:

enum Color {
  Red = 0xFF0000,
  Green = 0x00FF00,
  Blue = 0x0000FF
}
const yellow: Color = Color.Red | Color.Green; // 0xFFFF00
const white: Color = Color.Red | Color.Green | Color.Blue; // 0xFFFFFF
const blue: Color = white & ~yellow; // 0x0000FF
Run Code Online (Sandbox Code Playgroud)

并且因为枚举的这种使用存在于现实世界的代码中,所以改变这种行为将是一个突破性的变化。而且该语言的维护者似乎并不特别倾向于尝试.

因此,无论好坏,数字枚举被松散地键入为主要与number.


可以滚动您自己的更严格的类似 enum 的对象,但它涉及手动完成许多使用enum语法时自动发生的事情。这是一种可能的实现(它不会为您提供反向映射):

namespace MyEnum {
  export const Zero = 0;
  export type Zero = typeof Zero;

  export const One = 1;
  export type One = typeof One;

  export const Two = 2;
  export type Two = typeof Two;
}
type MyEnum = typeof MyEnum[keyof typeof MyEnum];

const foo: MyEnum.Zero = 0 // okay
const bar: MyEnum.Zero = 1 // error!
Run Code Online (Sandbox Code Playgroud)

其工作原理如下...当您编写 时enum X { Y = 123, Z = 456 },TypeScript 在运行时引入了一个名为 的值X,具有属性X.YX.Z。它还引入了类型命名XX.YX.Z。类型X.YandX.Z只是值X.Y和的类型X.Z。但类型X不是值的类型X。相反,它是属性类型的联合X.Y | X.Z

我使用namespaceexportconsttype以上来达到类似的效果。但这里的区别在于数字枚举的可分配性规则不适用,因此您将获得您期望的严格类型检查。

好的,希望有帮助;祝你好运!

代码链接