TypeScript - 枚举与常量枚举的互换性

eth*_*ane 6 enums typescript

tsc只要两个枚举名称和每个枚举成员相同,就允许两个不同枚举声明的基本互换使用。例如,下面的赋值是有效的,namespaces在这里使用,但是观察到这扩展到 TS 模块声明和单独的文件。

namespace X {
      export enum Colour {
            Blue,
            Green,
            
      }
}

namespace Y {
      export enum Colour {
            Green,
            Blue
      }
}

// assign a Colour enum from Y to a variable with a Colour enum type from X
let greenXY: X.Colour = Y.Colour.Green; // OK

// assign a Colour enum from X to a variable with a Colour enum type from Y
let blueYX: Y.Colour = X.Colour.Blue; // OK

// and equality
let greenX = X.Colour.Green;
let isGreen = greenX == Y.Colour.Green; // OK
Run Code Online (Sandbox Code Playgroud)

现在考虑const具有相同结构的枚举:

namespace X {
      export const enum ConstColour {
            Green,
            Blue
      }
}

namespace Y {
      export const enum ConstColour {
            Green,
            Blue
      }
}

// assign a const Colour enum from Y to a variable with a const Colour enum type from X
let greenConstXY: X.ConstColour = Y.ConstColour.Green; // Type 'ConstColour.Green' is not assignable to type 'ConstColour'.(2322)

// assign a Colour enum from Y to a variable with a Colour enum type from X
let blueConstYX: Y.ConstColour = X.ConstColour.Blue; // Type 'ConstColour.Blue' is not assignable to type 'ConstColour'.(2322)

// and equality
let constGreenX = X.ConstColour.Green;
let isConstGreen = constGreenX == Y.ConstColour.Green; // This condition will always return 'false' since the types 'X.ConstColour' and 'Y.ConstColour' have no overlap.(2367)
Run Code Online (Sandbox Code Playgroud)

我们知道const枚举在使用站点上内联到所需的值,并且tsc将枚举视为其成员的联合类型,这就是tsc知道枚举所包含的类型。

因此,如果tsc能够在编译时可靠地确定两个常规枚举的正确基本用法。为什么const在这种情况下枚举会有所不同?

游乐场链接

jca*_*alz 4

不幸的是,一个已知的错误microsoft/TypeScript#29879使您感到困惑。enum两者都不能const enum以这种方式互换。我看到你提到 TS 支持这一点,如果它们具有相同的名称,但在不同的命名空间中具有相同的名称应该没有任何意义......并且如果您更改声明enum以使它们具有不同的名称(例如,ColorinXColourin Y) :

namespace X {
      export enum Color {
            Green,
            Blue,               
      }
}

namespace Y {
      export enum Colour {
            Green,
            Blue
      }
}
Run Code Online (Sandbox Code Playgroud)

你会得到与你的错误相同的错误const enum

let greenXY: X.Color = Y.Colour.Green; // error!
let blueYX: Y.Colour = X.Color.Blue; // error!
let greenX = X.Color.Green;
let isGreen = greenX == Y.Colour.Green; // error!
Run Code Online (Sandbox Code Playgroud)

不同命名空间中同名的可分配性enum并不是有意为之;这是一个奇怪的错误,而且显然还不够重要,无法在短期内修复(它已被归入积压工作


不知道该怎么告诉你该怎么做。就我个人而言,我尽可能远离enums,因为它们是一个较旧的功能,不符合TypeScript 的设计目标enum…… ECMAScript 中没有s。如今,任何向 TypeScript 添加类似功能的提案(如果您实现新的表达式级语法,而无需首先存在于至少ECMAScript 的第 3 阶段提案中),都将被拒绝。

相反,enum我有时会推出自己的等价物,例如:

namespace U {
      export const Colour = {
            Green: 0,
            Blue: 1
      } as const;
      export type Colour = typeof Colour[keyof typeof Colour];
}
namespace V {
      export const Colour = {
            Green: 0,
            Blue: 1
      } as const;
      export type Colour = typeof Colour[keyof typeof Colour];

}
Run Code Online (Sandbox Code Playgroud)

这更乏味,但在我看来,表现更好,因为类型Colour只是数字文字的联合0 | 1,它们总是可以互换的:

let greenUV: U.Colour = V.Colour.Green;
let greenVU: V.Colour = U.Colour.Green;
let greenU = U.Colour.Green;
let isGreenU = greenU === V.Colour.Green;
Run Code Online (Sandbox Code Playgroud)

但那只是我的个人意见。


无论如何,希望这有助于理解这种情况。祝你好运!

Playground 代码链接