typescript - Sử dụng giá trị tính toán trên enum
Tôi có tình huống sau:
enum T {
A = "a"
};
enum U {
[T.A] = "u"
}
Tôi nhận được lỗi này:
Tên thuộc tính tính toán không được phép trong enum.
Có cách nào để khắc phục nó không? Hoặc có thể sử dụng một nguồn tài nguyên tương tự giúp tôi có được hành vi tương tự không?
Câu trả lời #1
Một lựa chọn, mặc dù không nhất thiết là lý tưởng, là sử dụng các giá trị rõ ràng từ enum T rồi thực hiện một số câu lệnh xác nhận thời gian biên dịch bằng cách sử dụng định nghĩa kiểu giả:
enum T {
A = "a"
};
enum U {
// T.A
a = "u"
}
/** this raises a compile error if not all values of enum T are valid keys of the enum U */
type _ensure_keyof_U_equals_T = typeof U[T];
Lưu ý là bạn thực sự sẽ không sử dụng _ensure_keyof_U_equals_T ở bất kỳ đâu khác trong mã, nó chỉ tồn tại để gây ra lỗi kiểu nếu enum không khớp với cấu trúc bạn muốn. (ví dụ playground) nếu T chứa một phần tử không tồn tại trong U, nó sẽ báo lỗi nói rằng "typeof U không có thuộc tính ___", vì vậy bạn phải đảm bảo T chứa thuộc tính đó để mã có thể biên dịch. một cách vòng vèo nhưng vẫn hiệu quả.
Điều này nhằm đảm bảo rằng một giá trị của kiểu T có thể được sử dụng như một khóa động vào đối tượng U được tạo ra tại thời gian chạy. Lưu ý rằng một trong những lợi ích của enum là có thể làm cho chúng trở thành const, điều mà không phải là một tùy chọn với loại kiến trúc này.
Một lựa chọn thay thế là làm U thành một định nghĩa đối tượng thay vì một enum như sau:
type U = (typeof U)[keyof typeof U]
const U = {
[T.A]: "u"
} as const
Điều này không khẳng định rằng mọi phần tử có thể có của T đều là một khóa hợp lệ (mặc dù _ensure_keyof_U_equals_T ở trên vẫn sẽ hoạt động chính xác như vậy ở đây) nhưng tạo ra một sự kết hợp đối tượng/loại gần như không thể phân biệt được với trường hợp enum, sự khác biệt duy nhất là các kiểm tra cho các chuỗi ký tự có phần lỏng lẻo hơn một chút:
enum A {
a = "b"
}
type B = (typeof B)[keyof typeof B];
const B = {
element: "b"
} as const
function should_only_accept_enum_A(item: A){}
function should_only_accept_enum_B(item: B){}
should_only_accept_enum_A("b") // fails
should_only_accept_enum_B("b") // succeeds
Nhưng nếu bạn muốn đưa các giá trị không phải chuỗi vào cấu trúc đó, điều này giống như trường hợp mà bạn sẽ làm việc này, nó vẫn cho phép điều đó.
