Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

不推荐使用 Enum 类型 #21

Open
nmsn opened this issue Jul 11, 2022 · 3 comments
Open

不推荐使用 Enum 类型 #21

nmsn opened this issue Jul 11, 2022 · 3 comments

Comments

@nmsn
Copy link
Owner

nmsn commented Jul 11, 2022

来源:https://react-typescript-cheatsheet.netlify.app/docs/basic/troubleshooting/types

推荐使用联合类型代替枚举类型

枚举的问题

  1. enum 编译后的内容庞大(使用 const enum 能解决这个问题,但容易混淆)
enum Direction {
  Up,
  Down,
  Left,
  Right,
}

// output
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
  1. 数字类型的枚举不安全(字符串没事)
enum Direction {
  Up,
  Down,
  Left,
  Right,
}

function move(direction: Direction) {
    console.log(direction);
}

move(30); // ok

这种执行不会报错

  1. 字符串枚举不能直接使用字符串赋值
enum Status {
  Admin = "Admin",
  User = "User",
  Moderator = "Moderator",
}

declare function closeThread(threadId: number, status: Status): void;

closeThread(10, "Admin");
//              ^ 💥 This is not allowed!


closeThread(10, Status.Admin);
//              ^ You have to be explicit!

使用联合类型更好

  1. 简单形式
type Status = "Admin" | "User" | "Moderator"

declare function closeThread(threadId: number, status: Status): void;

closeThread(10, "Admin");
// All good 😄
  1. 类枚举风格
const Direction = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
} as const;

// Get to the const values of any object
type Values<T> = T[keyof T];

// Values<typeof Direction> yields 0 | 1 | 2 | 3
declare function move(
  direction: Values<typeof Direction>): void;

move(30);
//   ^ 💥 This breaks!

move(0);
//   ^ 👍 This works!

move(Direction.Left);
//   ^ 👍 This also works!

// And now for the Status enum

const Status = {
  Admin: "Admin",
  User: "User",
  Moderator: "Moderator"
} as const;

// Values<typeof Status> yields "Admin" | "User" | "Moderator"
declare function closeThread(
  threadId: number, 
  status: Values<typeof Status>): void;

closeThread(10, "Admin"); // All good!
closeThread(10, Status.User); // enum style

这些方法不会导致出现枚举存在的问题

@nmsn
Copy link
Owner Author

nmsn commented Mar 24, 2023

使用 Enum 违背了一个原则:

去掉 Typescript 类型,剩下的 Javascript 还是具有完整功能,Typescript 只是增加了静态类型

Enum 的使用,使得需要增加额外的代码来保证功能的完善(另外不推荐使用的 namespace 也打破了这个规则)

@nmsn
Copy link
Owner Author

nmsn commented Mar 24, 2023

在 TypeScript 中,const enum 和 enum 都用于定义枚举类型,但它们之间有一些重要的区别。

enum 是一种可以为一组相关的数值赋予有意义的名字的方式。它会在运行时被编译成一个对象,该对象包含枚举成员的名称和对应的值。例如:

enum Color {
  Red,
  Green,
  Blue,
}

在运行时,Color 会被编译成以下对象:

{
  "0": "Red",
  "1": "Green",
  "2": "Blue",
  "Red": 0,
  "Green": 1,
  "Blue": 2,
}

使用枚举时,可以通过枚举成员的名称或值来引用它们。例如,Color.Red 的值为 0,Color[0] 的值为 "Red"。

const enum 是一种更为轻量级的枚举类型,它在编译时被完全删除。这意味着在运行时不存在 const enum 的值,因此不能通过枚举成员的名称来引用它们。相反,可以直接使用枚举成员的值。例如:

const enum Color {
  Red,
  Green,
  Blue,
}

console.log(Color.Red); // 编译后输出 0

由于 const enum 在编译时被删除,因此它的使用会减少 JavaScript 代码的大小。但请注意,如果使用 const enum 的代码被其他代码引用,那么它们的代码大小可能会增加。因此,建议只在确信不需要在其他代码中使用枚举时才使用 const enum.

@nmsn
Copy link
Owner Author

nmsn commented Mar 24, 2023

enum 不支持 Tree-Shaking前段时间有同事说没有用到的 enum 定义被打到了包里,我当时觉得这不太可能,编译成 JS 就是一个普通的变量而已,怎么可能不被 Tree-Shaking ?但是经过实验,我发现这玩意儿确实无法 Tree-Shaking 。查看编译结果,我发现 enum 声明并不会简单的转义成一个变量声明。我们来看一个例子:

enum T {
  A,
  B,
  C
}

上面这段代码会被转译成:

"use strict";
var T;
(function (T) {
    T[T["A"] = 0] = "A";
    T[T["B"] = 1] = "B";
    T[T["C"] = 2] = "C";
})(T || (T = {}));

转义后的这段代码里有一个带 副作用 的立即执行函数,这就是无法被 Tree-Shaking 的根本原因。

来源:https://www.zhihu.com/question/60168510/answer/2873783076

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant