Cùi Bắp
bởi Cùi Bắp
5 phút để đọc

Chuyên mục

Tags

Khi sử dụng TypeScript, chúng ta thường gặp phải trường hợp xác định kiểu của một biến mà giá trị của nó rơi vào một hay nhiều khả năng khác nhau.

Ví dụ, status của một button có thể là: "hidden", "enabled", "disabled".

Với Typescript chúng ta có ít nhất hai cách

// Kiểu string enums
export enum ButtonStatus {
  HIDDEN = 'HIDDEN',
  ENABLED = 'ENABLED',
  DISABLED = 'DISABLED',
};

// Kiểu string literal union types
type ButtonStatus = 'HIDDEN' | 'ENABLED' | 'DISABLED';

Có cũng có kiểu enum cơ bản (không có phần = 'HIDDEN'), khi đó các giá trị sẽ chạy từ 0 → 2, nhưng ta sẽ không bàn về nó trong bài viết so sánh này.

Nào, hãy bắt đầu so sánh coi 🥰

Declaring & Accessing

  • Tính ngắn gọn trong khai báo
    • [✔] Union Type
    • [✘] String Enums
  • Autocompletion trên Editor/IDE
    • [✔] Union Type
      • Tự động nhận trên VsCode
    • [✘] String Enums
      • Cần exported và imported mới hoạt động

Chiến thắng với 2 points cho Union types!

Union Type String Enums
2 0

Extending

  • [✔] Union Type
    type DynamicButtonStatus = ButtonStatus | 'LOADING';
    
  • [✘] String Enums
    • Sử dụng trick spread operator
      export enum ButtonStatus {
        HIDDEN = 'HIDDEN',
        ENABLED = 'ENABLED',
        DISABLED = 'DISABLED',
      };
      
      // extend enum using "spread"
      const NewButtonStatus = {
          ...ButtonStatus,
          SHOW: 'SHOW',
          BLINK: 'BLINK'
      };
      

Thêm 1 point cho Union types!

Union Type String Enums
3 0

TypeError

  • [✔] Union Type
    • Playground Link
      // With union types of string literals
      type ButtonStatus = 'HIDDEN' | 'ENABLED' | 'DISABLED';
      
      function TestUnionType(status: ButtonStatus) {
        switch (status) {
          case 'HIDDEN': return 1;
          case 'ENABLED': return 2;
          case 'DISABLED': return 3;
          // Notice that there's no default case
        }
      }
      
      // Compile success if pass valid status with Union Type
      console.log(TestUnionType('HIDDEN'));
      
      // Compile error if pass invalid status with Union Type
      console.log(TestUnionType('SHOW'));
      
    • Error được phát hiện từ bước Transpile
      Argument of type '"SHOW"' is not assignable to parameter of type 'ButtonStatus'.
      
  • [✘] String Enums
    • Playground Link
      // With string enums
      enum ButtonStatus {
        HIDDEN = 'HIDDEN',
        ENABLED = 'ENABLED',
        DISABLED = 'DISABLED'
      };
      
      
      function TestStringEnums(status: ButtonStatus) {
        switch (status) {
          case ButtonStatus.HIDDEN: return 1;
          case ButtonStatus.ENABLED: return 2;
          case ButtonStatus.DISABLED: return 3;
          default: return 4;
        }
      }
      
      const status1 = 'HIDDEN' as ButtonStatus;
      
      // Compile success if pass valid status with String Enums
      console.log(TestStringEnums(status1));
      
      const status2 = 'SHOW' as ButtonStatus;
      
      // NO Compile error if pass invalid status with String Enums
      console.log(TestStringEnums(status2));
      
    • Truyền sai giá trị status2 nhưng chương trình vẫn được transpiled và run bình thường.

Chỉ có 1 cách duy nhất để sử dụng union types, trong khi với enums bạn có thể sử dụng ButtonStatus.HIDDEN hoặc giá trị trực tiếp 'HIDDEN' mà không gặp phải compiler complaining.

Thêm 1 point về Typesafe cho Union types!

Union Type String Enums
4 0

Iterating

  • [✘] Union Type
    // Union types
    // ? Can't iterate over a type, defining an array is needed
    const ButtonStatus = ['HIDDEN', 'ENABLED', 'DISABLED'] as const;
    // Notice that the array and type can have the same name if you want
    type ButtonStatus = typeof buttonStatuses[number];
    
    for(const status of buttonStatus) {
      // ? the type of status here is ButtonStatus
      // ? always iterate in order
    }
    
  • [✔] String Enums
    // String enums
    // ? Just do it
    for(const status in ButtonStatus) {
      // ? The type of status here is string
      // ? iteration order not guaranteed with "in"
    }
    

Trả lại 1 point cho String Enums

Union Type String Enums
4 1

Renaming

  • [✘] Union Type
    • Find and replace toàn Project
  • [✔] String Enums
    • Right click > Rename symbol

Rõ ràng String Enums tiện hơn, trả thêm 1 point cho String Enums

Union Type String Enums
4 2

Tổng kết

Trong bài viết so sánh trên quan điểm cá nhân mình thì Union Type nhận được 4 điểmString Enums nhận được 2 điểm!

Hãy sử dụng Union types by default :laughing:

Nếu bạn có quan điểm khác, hãy để lại comment dưới bài viết này, xin chân thành cảm ơn các góp ý từ bạn đọc 🌺