Với các phiên bản gần đây của TypeScript, thật dễ dàng khai báo các kiểu liên hợp có thể lặp lại. Do đó, bạn nên thích các loại liên minh hơn enums.
Cách khai báo các kiểu liên hợp có thể lặp lại
const permissions = ['read', 'write', 'execute'] as const;
type Permission = typeof permissions[number];
for (const permission of permissions) {
}
Khi các giá trị thực tế của kiểu liên hợp không mô tả chính xác chúng, bạn có thể đặt tên chúng như cách bạn làm với enum.
enum Permission {
Read = 'r',
Write = 'w',
Execute = 'x'
}
const Permission = {
Read: 'r',
Write: 'w',
Execute: 'x'
} as const;
type Permission = typeof Permission[keyof typeof Permission];
for (const permission of Object.values(Permission)) {
}
Đừng bỏ lỡ as const
khẳng định đóng vai trò quan trọng trong các mô hình này.
Tại sao nó không tốt để sử dụng enums?
1. Các enum non-const không phù hợp với khái niệm "một tập hợp JavaScript được đánh máy"
Tôi nghĩ rằng khái niệm này là một trong những lý do quan trọng khiến TypeScript trở nên phổ biến trong các ngôn ngữ altJS khác. Các enums không phải const vi phạm khái niệm bằng cách tạo ra các đối tượng JavaScript sống trong thời gian chạy với cú pháp không tương thích với JavaScript.
2. Const enums có một số cạm bẫy
Const enums không thể được chuyển đổi với Babel
Hiện tại có hai cách giải quyết cho vấn đề này: loại bỏ const enums theo cách thủ công hoặc bằng plugin babel-plugin-const-enum
.
Khai báo const enums trong bối cảnh xung quanh có thể có vấn đề
Không cho phép sử dụng hằng số xung quanh khi --isolatedModules
cờ được cung cấp. Một thành viên trong nhóm TypeScript nói rằng " const enum
trên DT thực sự không có ý nghĩa" (DT đề cập đến DefiniedlyTyped) và "Bạn nên sử dụng kiểu liên hợp của các ký tự (chuỗi hoặc số) thay vì" const enums trong ngữ cảnh xung quanh.
Const enums under --isolatedModules
flag hoạt động kỳ lạ ngay cả khi ở bên ngoài bối cảnh xung quanh
Tôi đã rất ngạc nhiên khi đọc nhận xét này trên GitHub và xác nhận rằng hành vi vẫn đúng với TypeScript 3.8.2.
3. Các ô số không phải là loại an toàn
Bạn có thể gán bất kỳ số nào cho enums dạng số.
enum ZeroOrOne {
Zero = 0,
One = 1
}
const zeroOrOne: ZeroOrOne = 2;
4. Khai báo chuỗi enums có thể thừa
Đôi khi chúng ta thấy loại enums chuỗi này:
enum Day {
Sunday = 'Sunday',
Monday = 'Monday',
Tuesday = 'Tuesday',
Wednesday = 'Wednesday',
Thursday = 'Thursday',
Friday = 'Friday',
Saturday = 'Saturday'
}
Tôi phải thừa nhận rằng có một tính năng enum mà các loại liên minh không đạt được
Ngay cả khi rõ ràng từ ngữ cảnh rằng giá trị chuỗi được bao gồm trong enum, bạn không thể gán nó cho enum.
enum StringEnum {
Foo = 'foo'
}
const foo1: StringEnum = StringEnum.Foo;
const foo2: StringEnum = 'foo';
Điều này thống nhất kiểu gán giá trị enum trong toàn bộ mã bằng cách loại bỏ việc sử dụng các giá trị chuỗi hoặc các ký tự chuỗi. Hành vi này không phù hợp với cách hệ thống kiểu TypeScript hoạt động ở những nơi khác và khá đáng ngạc nhiên và một số người nghĩ rằng điều này nên được khắc phục các vấn đề đã nêu ra ( điều này và điều này ), trong đó nó được đề cập nhiều lần rằng mục đích của chuỗi enums là để cung cấp các loại chuỗi "không rõ ràng": tức là chúng có thể được thay đổi mà không cần sửa đổi người tiêu dùng.
enum Weekend {
Saturday = 'Saturday',
Sunday = 'Sunday'
}
const weekend: Weekend = Weekend.Saturday;
Lưu ý rằng "độ mờ" này không hoàn hảo vì việc gán giá trị enum cho các kiểu chuỗi ký tự là không giới hạn.
enum Weekend {
Saturday = 'Saturday',
Sunday = 'Sunday'
}
const saturday: 'Saturday' = Weekend.Saturday;
Nếu bạn nghĩ rằng tính năng "không rõ ràng" này có giá trị đến mức bạn có thể chấp nhận tất cả những nhược điểm mà tôi đã mô tả ở trên để đổi lấy nó, bạn không thể từ bỏ chuỗi enums.
Cách loại bỏ enums khỏi codebase của bạn
Với no-restricted-syntax
quy tắc của ESLint, như đã mô tả .