0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

So sánh TypeScript Enums: `const enum`, `enum` và `object as const`

Đăng vào 8 tháng trước

• 6 phút đọc

Chủ đề:

#webdev#typescript

Giới thiệu

Khi làm việc với TypeScript, các lập trình viên thường cần đại diện cho một tập hợp các hằng số liên quan. Mặc dù các enum truyền thống là lựa chọn rõ ràng, TypeScript cung cấp nhiều phương pháp khác nhau, mỗi phương pháp có những ưu điểm và nhược điểm riêng. Trong bài viết này, chúng ta sẽ khám phá ba phương pháp chính: const enum, enum thông thường và object với as const, giúp bạn đưa ra quyết định thông minh cho dự án của mình.

1. Enum thông thường (enum)

Định nghĩa: Enum truyền thống tồn tại cả trong thời gian biên dịch và thời gian chạy.

typescript Copy
export enum UserRole {
  Admin = "ADMIN",
  User = "USER",
  Guest = "GUEST"
}

Kết quả biên dịch:

typescript Copy
export var UserRole;
(function (UserRole) {
    UserRole["Admin"] = "ADMIN";
    UserRole["User"] = "USER";
    UserRole["Guest"] = "GUEST";
})(UserRole || (UserRole = {}));

Ưu điểm:

  • Tồn tại tại thời gian chạy: Đối tượng đầy đủ có sẵn trong quá trình thực thi
  • Hỗ trợ phản chiếu: Có thể lặp lại, xác thực và kiểm tra các giá trị
  • Tính tương thích giữa các module: Hoạt động liền mạch qua các ranh giới tệp
  • Cú pháp quen thuộc: Hành vi enum truyền thống từ các ngôn ngữ khác

Nhược điểm:

  • Kích thước gói lớn hơn: Tạo mã JavaScript bổ sung
  • Khả năng loại bỏ cây kém: Khó loại bỏ các giá trị không sử dụng
  • Chi phí hiệu suất: Tạo đối tượng và truy cập thuộc tính

Phù hợp nhất cho: API công khai, xác thực tại thời gian chạy và các tình huống cần phản chiếu.

2. Const Enums (const enum)

Định nghĩa: Enum chỉ tồn tại tại thời gian biên dịch và hoàn toàn bị xóa khỏi đầu ra JavaScript.

typescript Copy
export const enum HttpStatus {
  OK = 200,
  Created = 201,
  NotFound = 404,
  ServerError = 500
}

Kết quả biên dịch: Các giá trị được nhúng trực tiếp nơi chúng được sử dụng:

typescript Copy
// Thay vì HttpStatus.OK, bạn có:
const status = 200;

Ưu điểm:

  • Không có chi phí tại thời gian chạy: Không có mã JavaScript được tạo ra
  • Hiệu suất tuyệt vời: Các giá trị được nhúng trực tiếp
  • Khả năng loại bỏ cây hoàn hảo: Không còn mã không sử dụng
  • Kích thước gói nhỏ: Ảnh hưởng tối thiểu đến bản dựng cuối cùng

Nhược điểm:

  • Không có quyền truy cập tại thời gian chạy: Không thể lặp lại hoặc phản chiếu
  • Vấn đề ranh giới module: Vấn đề với biên dịch độc lập
  • Thách thức trong gỡ lỗi: Tên enum gốc có thể bị mất

Phù hợp nhất cho: Các hằng số nội bộ, mã nhạy cảm với hiệu suất và ánh xạ giá trị đơn giản.

3. Object với as const

Định nghĩa: Phương pháp hiện đại của TypeScript sử dụng các đối tượng đơn giản với các khẳng định const.

typescript Copy
export const UserRole = {
  Admin: "ADMIN",
  User: "USER",
  Guest: "GUEST"
} as const;

export type UserRole = typeof UserRole[keyof typeof UserRole];

Kết quả biên dịch: (Giống như đầu vào)

typescript Copy
export const UserRole = {
  Admin: "ADMIN",
  User: "USER",
  Guest: "GUEST"
};

Ưu điểm:

  • Không có chi phí tại thời gian chạy: Đối tượng đơn giản, không có mã phát sinh thêm
  • An toàn kiểu hoàn toàn: Tích hợp đầy đủ với TypeScript
  • Quyền truy cập tại thời gian chạy: Đối tượng đầy đủ có sẵn để phản chiếu
  • Mẫu hiện đại: Phù hợp với sự phát triển của TypeScript
  • Giá trị linh hoạt: Có thể kết hợp các kiểu (chuỗi, số, v.v.)

Nhược điểm:

  • Trích xuất kiểu thủ công: Cần định nghĩa kiểu bổ sung
  • Không có ánh xạ ngược tích hợp: Khác với các enum số
  • Có phần dài dòng hơn: Cần hai khai báo

Phù hợp nhất cho: Các mã nguồn hiện đại, các kiểu giá trị hỗn hợp và khi cần cả quyền truy cập tại thời gian biên dịch lẫn thời gian chạy.

Phân tích so sánh

Tác động đến kích thước gói

typescript Copy
// enum: ~150 bytes được tạo
enum Colors { Red, Green, Blue }

// const enum: 0 bytes được tạo  
const enum Colors { Red, Green, Blue }

// object as const: ~50 bytes (chỉ đối tượng)
const Colors = { Red: 0, Green: 1, Blue: 2 } as const

Hiệu suất tại thời gian chạy

typescript Copy
// enum: Truy cập thuộc tính đối tượng
const color = Colors.Red;

// const enum: Giá trị nhúng trực tiếp (nhanh nhất)
const color = 0;

// object as const: Truy cập thuộc tính đối tượng
const color = Colors.Red;

An toàn kiểu

Cả ba phương pháp đều cung cấp an toàn kiểu tuyệt vời, nhưng object as const cung cấp sự linh hoạt nhất với các kiểu hỗn hợp:

typescript Copy
// Chỉ có thể với object as const
const Status = {
  Active: "ACTIVE",
  Pending: 0,
  Disabled: "DISABLED"
} as const;

Ví dụ thực tiễn

Tình huống 1: Xử lý phản hồi API

typescript Copy
// Tốt nhất: object as const (cần xác thực tại thời gian chạy)
export const ApiErrorCode = {
  NotFound: "NOT_FOUND",
  Unauthorized: "UNAUTHORIZED",
  ServerError: "SERVER_ERROR"
} as const;

export type ApiErrorCode = typeof ApiErrorCode[keyof typeof ApiErrorCode];

function handleError(code: ApiErrorCode) {
  if (Object.values(ApiErrorCode).includes(code)) {
    // Mã lỗi hợp lệ
  }
}

Tình huống 2: Hằng số nội bộ

typescript Copy
// Tốt nhất: const enum (chỉ tại thời gian biên dịch)
export const enum Direction {
  Up = 1,
  Down = 2,
  Left = 3,
  Right = 4
}

function move(direction: Direction) {
  // Các giá trị được nhúng: direction === 1, v.v.
}

Tình huống 3: API thư viện công khai

typescript Copy
// Tốt nhất: enum thông thường (tính tương thích tại thời gian chạy)
export enum LogLevel {
  Error = 0,
  Warn = 1,
  Info = 2,
  Debug = 3
}

// Người tiêu dùng có thể lặp lại hoặc xác thực
console.log(Object.values(LogLevel));

Ví dụ di chuyển

Từ enum truyền thống:

typescript Copy
enum OldStyle {
  Value1 = "VALUE1",
  Value2 = "VALUE2"
}

Đến object as const hiện đại:

typescript Copy
const NewStyle = {
  Value1: "VALUE1",
  Value2: "VALUE2"
} as const;

type NewStyle = typeof NewStyle[keyof typeof NewStyle];

Hướng dẫn quyết định

Trường hợp sử dụng Phương pháp được khuyến nghị
API thư viện công khai enum
Mã nhạy cảm với hiệu suất const enum
Xác thực tại thời gian chạy object as const
Các kiểu giá trị hỗn hợp object as const
Mã nguồn cũ enum (tính nhất quán)
Dự án mới object as const
Sử dụng giữa các module enum hoặc object as const

Thực tiễn tốt nhất

  1. Sử dụng object as const cho hầu hết các phát triển mới
  2. Giữ const enum cho các hằng số nhạy cảm với hiệu suất
  3. Chọn enum khi xuất bản thư viện cho người tiêu dùng rộng rãi
  4. Xem xét công cụ: Một số công cụ xây dựng xử lý const enum kém
  5. Giữ nhất quán trong mã nguồn của bạn

Kết luận

TypeScript cung cấp nhiều cách để xử lý các hằng số, mỗi cách phục vụ cho những nhu cầu khác nhau:

  • enum: Lựa chọn truyền thống cho quyền truy cập tại thời gian chạy và tính tương thích
  • const enum: Tối ưu hóa hiệu suất cho các giá trị chỉ tại thời gian biên dịch
  • object as const: Cách tiếp cận hiện đại, linh hoạt cho hầu hết các trường hợp sử dụng

Hiểu rõ những tùy chọn này cho phép bạn viết mã TypeScript hiệu quả và dễ bảo trì hơn. Đối với hầu hết các ứng dụng hiện đại, object as const cung cấp sự cân bằng tốt nhất giữa an toàn kiểu, quyền truy cập tại thời gian chạy và hiệu quả kích thước gói, trong khi const enum vẫn có giá trị cho các tình huống nhạy cảm với hiệu suất và enum giữ vị trí của nó trong các API công khai và mã nguồn cũ.

Hãy chọn dựa trên nhu cầu cụ thể của bạn, và nhớ rằng tính nhất quán trong một dự án thường quan trọng hơn sự tối ưu hoàn hảo.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào