javascript - Lập chỉ mục một đối tượng enum với khóa không phân biệt chữ hoa chữ thường trong TypeScript
Mặc dù không cần thiết, các khóa enum thường được khai báo toàn bộ bằng CHỮ IN HOA. Tuy nhiên, giá trị của enum có thể khác với chính khóa.
declare enum MyEnum {
PRODUCTION = "production",
DEVELOPMENT = "development",
SANDBOX = "sandbox"
}
Nếu tôi sử dụng một giá trị chuỗi bên ngoài khớp với giá trị enum của mình để lập chỉ mục cho enum, nó sẽ không hoạt động vì khóa không giống với giá trị:
const lowercase = "production";
const UPPERCASE = "PRODUCTION";
const bad = MyEnum[lowercase]; // does not work
const good = MyEnum[UPPERCASE]; // works
Tôi muốn sử dụng giá trị enum như một cách để lập chỉ mục cho enum. Liệu tôi có bị buộc phải luôn khớp chính xác giá trị enum và khóa enum để có thể lập chỉ mục cho enum một cách động, hay tôi phải sử dụng một số thao tác với giá trị chuỗi để đảm bảo khóa khớp với giá trị?
Câu trả lời #1
Các enum trong TypeScript được phát ra dưới dạng các đối tượng JavaScript thuần túy. Do đó, đến một mức độ nào đó, câu hỏi này thực sự liên quan đến cách bạn có thể truy cập các đối tượng JavaScript với khóa không phân biệt chữ hoa chữ thường. Câu trả lời ngắn gọn là bạn không thể và bạn cần tìm cách giải quyết vấn đề này. Câu trả lời dài hơn là bạn có thể xây dựng một Proxy cho đối tượng của mình sao cho nó hoạt động theo cách bạn muốn, nhưng điều này sẽ phức tạp hơn nhiều so với chỉ tìm cách giải quyết vấn đề, đặc biệt là bất cứ thứ gì có thể thuyết phục TypeScript rằng đây là những gì bạn đang làm.
Nếu bạn biết rằng tất cả các khóa của đối tượng đều được viết hoa, thì cách giải quyết dễ dàng nhất là tự chuyển khóa ứng viên sang chữ hoa trước khi truy cập vào đối tượng. TypeScript không hiểu phương thức toUpperCase() của string sẽ làm gì với các kiểu literal của chuỗi. Ví dụ, nếu bạn có một giá trị v có kiểu "foo", trình biên dịch sẽ không hiểu rằng v.toUpperCase() là một giá trị có kiểu "FOO":
let x: "FOO" = "foo".toUpperCase(); // error!
nhưng bạn có thể viết một lớp bọc cho phương thức toUpperCase() có cách hoạt động như sau:
const uc = <T extends string>(x: T) => x.toUpperCase() as Uppercase<T>;
let x: "FOO" = uc("foo"); // okay
Ở đây uc đang sử dụng kiểu nội tại Uppercase<T> trong kiểu trả về của nó.
Vì vậy, cách giải quyết ở đây là chỉ cần truyền các khóa qua uc() trước khi lập chỉ mục:
const UPPERCASE = "PRODUCTION";
const good = MyEnum[uc(UPPERCASE)]; // okay
// const good: MyEnum.PRODUCTION
const lowercase = "production";
const stillGood = MyEnum[uc(lowercase)]; // okay
// const stillGood: MyEnum.PRODUCTION
Nếu bạn không biết rằng tất cả các khóa đều viết hoa thì bạn cần phải tìm kiếm trong đối tượng của mình để tìm một khóa phù hợp. Bạn có thể viết một hàm trợ giúp thực hiện việc này, và thậm chí cung cấp cho nó một chữ ký gọi mà TypeScript có thể sử dụng:
function idxIgnoreCase<K extends string, T extends object>(
obj: T,
k: K extends (
Uppercase<K> extends Uppercase<Extract<keyof T, string>> ? unknown : never
) ? K : Extract<keyof T, string>
): { [P in Extract<keyof T, string>]-?:
Uppercase<P> extends Uppercase<K> ? T[P] : never
}[Extract<keyof T, string>] {
return Object.entries(obj).find(
([p, v]) => k.toUpperCase() === p.toUpperCase())?.[1] as any;
}
Điều đó xấu xí, nhưng nó hiệu quả:
const ret = idxIgnoreCase(MyEnum, "dEvElOpMeNt");
// const ret: MyEnum.DEVELOPMENT
console.log(ret) // "development"
Tôi thậm chí sẽ không cố gắng viết hàm trợ giúp như một Proxy, vì làm như vậy sẽ yêu cầu nói với TypeScript rằng đối tượng kết quả có hàng trăm khóa, một cho mỗi trường hợp có thể có của các khóa gốc. Và tất cả chỉ để có lợi ích đáng ngờ là viết MyProxyEnum.dEvElOpMeNt thay vì f(MyEnum, "dEvElOpMeNt"). Đặc biệt là vì những nhà phát triển TypeScript và JavaScript khác khi nhìn vào mã có thể sẽ rất bối rối, vì họ đang mong đợi các khóa phân biệt chữ hoa chữ thường.
Một lần nữa, cách giải quyết bằng việc chỉnh sửa khóa trước khi lập chỉ mục vẫn là phương pháp dễ dàng và dễ hiểu nhất.
Liên kết Playground đến mã
Câu trả lời #2
Đây là quy ước đặt tên enum:
Sử dụng chữ in hoa cho các enum của bạn - chúng là các hằng số toàn cục có giá trị sử dụng được. Chúng không chỉ là các kiểu, mà thường được sử dụng như Foo hoặc TFoo.
Các khóa trên một enum thường viết hoa chữ cái đầu mỗi từ.
Tuy nhiên, trong trường hợp này, không cần phải sử dụng Enums
