prm*_*mph 38 enums unions typescript
自从TypeScript引入了联合类型以来,我想知道是否有任何理由声明枚举类型.请考虑以下枚举类型声明:
enum X { A, B, C }
var x:X = X.A;
Run Code Online (Sandbox Code Playgroud)
和类似的联合类型声明:
type X: "A" | "B" | "C"
var x:X = "A";
Run Code Online (Sandbox Code Playgroud)
如果它们基本上服务于同一目的,并且工会更强大和更具表现力,那么为什么需要枚举?
kim*_*ula 107
使用最新版本的 TypeScript,很容易声明可迭代的联合类型。因此,您应该更喜欢联合类型而不是枚举。
const permissions = ['read', 'write', 'execute'] as const;
type Permission = typeof permissions[number]; // 'read' | 'write' | 'execute'
// you can iterate over permissions
for (const permission of permissions) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
当联合类型的实际值不能很好地描述它们自己时,您可以像使用枚举一样命名它们。
// when you use enum
enum Permission {
Read = 'r',
Write = 'w',
Execute = 'x'
}
// union type equivalent
const Permission = {
Read: 'r',
Write: 'w',
Execute: 'x'
} as const;
type Permission = typeof Permission[keyof typeof Permission]; // 'r' | 'w' | 'x'
// of course it's quite easy to iterate over
for (const permission of Object.values(Permission)) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
不要错过as const在这些模式中起着关键作用的断言。
我认为这个概念是 TypeScript 在其他 altJS 语言中如此流行的关键原因之一。非常量枚举违反了这个概念,它发出的 JavaScript 对象存在于运行时,其语法与 JavaScript 不兼容。
目前有两种解决方法可以解决此问题:手动或使用 plugin 摆脱 const 枚举babel-plugin-const-enum。
--isolatedModules提供标志时,不允许使用环境常量枚举。一位 TypeScript 团队成员说“const enum在 DT 上确实没有意义”(DT 指的是绝对类型)和“您应该使用联合类型的文字(字符串或数字)代替”环境上下文中的 const 枚举。
--isolatedModules即使在环境上下文之外,标记下的常量枚举也表现得很奇怪我很惊讶地在 GitHub 上阅读了此评论,并确认该行为在 TypeScript 3.8.2 中仍然适用。
您可以为数字枚举分配任何数字。
enum ZeroOrOne {
Zero = 0,
One = 1
}
const zeroOrOne: ZeroOrOne = 2; // no error!!
Run Code Online (Sandbox Code Playgroud)
我们有时会看到这种字符串枚举:
enum Day {
Sunday = 'Sunday',
Monday = 'Monday',
Tuesday = 'Tuesday',
Wednesday = 'Wednesday',
Thursday = 'Thursday',
Friday = 'Friday',
Saturday = 'Saturday'
}
Run Code Online (Sandbox Code Playgroud)
即使从上下文中很明显字符串值包含在枚举中,您也不能将其分配给枚举。
enum StringEnum {
Foo = 'foo'
}
const foo1: StringEnum = StringEnum.Foo; // no error
const foo2: StringEnum = 'foo'; // error!!
Run Code Online (Sandbox Code Playgroud)
这通过消除使用字符串值或字符串文字来统一整个代码中枚举值分配的风格。这种行为与 TypeScript 类型系统在其他地方的行为方式不一致,有点令人惊讶,一些认为应该修复的人提出了问题(this和this),其中反复提到字符串枚举的意图是提供“不透明”字符串类型:即可以在不修改消费者的情况下更改它们。
enum Weekend {
Saturday = 'Saturday',
Sunday = 'Sunday'
}
// As this style is forced, you can change the value of
// Weekend.Saturday to 'Sat' without modifying consumers
const weekend: Weekend = Weekend.Saturday;
Run Code Online (Sandbox Code Playgroud)
请注意,这种“不透明性”并不完美,因为将枚举值分配给字符串文字类型不受限制。
enum Weekend {
Saturday = 'Saturday',
Sunday = 'Sunday'
}
// The change of the value of Weekend.Saturday to 'Sat'
// results in a compilation error
const saturday: 'Saturday' = Weekend.Saturday;
Run Code Online (Sandbox Code Playgroud)
如果你认为这个“不透明”特性是如此有价值,以至于你可以接受我上面描述的所有缺点来换取它,你就不能放弃字符串枚举。
随着no-restricted-syntaxESLint的规则,如描述。
mat*_*hew 19
您可能没有理由使用 enum
enum。 enumas flags。位标志 我看到使用联合的最大好处是,它们提供了一种简洁的方式来表示多种类型的值,并且可读性强。
let x: number | string
编辑:从TypeScript 2.4开始,枚举现在支持字符串。
enum Colors {
Red = "RED",
Green = "GREEN",
Blue = "BLUE",
}
Run Code Online (Sandbox Code Playgroud)
Rom*_*eau 18
枚举可以在概念上被视为联合类型的子集,专用于int和/或string值,在其他响应中提到了一些额外的功能,使它们易于使用,例如namespace。
关于类型安全,数字枚举不太安全,然后是联合类型,最后是字符串枚举:
// Numeric enum
enum Colors { Red, Green, Blue }
const c: Colors = 100; // ?? No errors!
// Equivalent union types
type Color =
| 0 | 'Red'
| 1 | 'Green'
| 2 | 'Blue';
let color: Color = 'Red'; // ?? No error because namespace free
color = 100; // ?? Error: Type '100' is not assignable to type 'Color'
type AltColor = 'Red' | 'Yellow' | 'Blue';
let altColor: AltColor = 'Red';
color = altColor; // ?? No error because `altColor` type is here narrowed to `"Red"`
// String enum
enum NamedColors {
Red = 'Red',
Green = 'Green',
Blue = 'Blue',
}
let namedColor: NamedColors = 'Red'; // ?? Error: Type '"Red"' is not assignable to type 'Colors'.
enum AltNamedColors {
Red = 'Red',
Yellow = 'Yellow',
Blue = 'Blue',
}
namedColor = AltNamedColors.Red; // ?? Error: Type 'AltNamedColors.Red' is not assignable to type 'Colors'.
Run Code Online (Sandbox Code Playgroud)
这篇 2ality 文章中有关该主题的更多信息:TypeScript 枚举:它们是如何工作的?它们可以用来做什么?
联合类型支持异构数据和结构,例如支持多态:
class RGB {
constructor(
readonly r: number,
readonly g: number,
readonly b: number) { }
toHSL() {
return new HSL(0, 0, 0); // Fake formula
}
}
class HSL {
constructor(
readonly h: number,
readonly s: number,
readonly l: number) { }
lighten() {
return new HSL(this.h, this.s, this.l + 10);
}
}
function lightenColor(c: RGB | HSL) {
return (c instanceof RGB ? c.toHSL() : c).lighten();
}
Run Code Online (Sandbox Code Playgroud)
在枚举和联合类型之间,单例可以代替枚举。它更冗长,但也更面向对象:
class Color {
static readonly Red = new Color(1, 'Red', '#FF0000');
static readonly Green = new Color(2, 'Green', '#00FF00');
static readonly Blue = new Color(3, 'Blue', '#0000FF');
static readonly All: readonly Color[] = [
Color.Red,
Color.Green,
Color.Blue,
];
private constructor(
readonly id: number,
readonly label: string,
readonly hex: string) { }
}
const c = Color.Red;
const colorIds = Color.All.map(x => x.id);
Run Code Online (Sandbox Code Playgroud)
我倾向于查看 F# 以了解良好的建模实践。引用F# enums on F#的一篇文章以获得乐趣和利润,在这里很有用:
一般来说,你应该更喜欢有区别的联合类型而不是枚举,除非你真的需要有一个
int(或一个string)与它们关联的值
模型枚举还有其他替代方法。其中一些在其他 2ality 文章中对 TypeScript 中的枚举的替代方法进行了很好的描述。
| 归档时间: |
|
| 查看次数: |
9655 次 |
| 最近记录: |