TypeScript / Use String As Enum Key
In TypeScript, you can define an enum and access its value with a string-like value, like this:
enum Editor {
VIM = 'Neovim',
EMACS = 'Emacs',
VSCODE = 'Visual Studio Code'
};
const key = 'VSCODE';
const editor = Editor[key];
In this example, the type of the key variable is not actually a string, but a literal type called ‘VSCODE’.
If you change the key definition from const to letor give it a type annotation, you will actually see that a string cannot be used to access enum values:
const key: string = 'VSCODE';
// or
let key = 'VSCODE';
const editor = Editor[key]; // ERROR!
// ^^^^^^^^^^^^
// Element implicitly has an 'any' type because expression
// of type 'string' can't be used to index type 'typeof Editor'.
// No index signature with a parameter of type 'string' was
// found on type 'typeof Editor'.(7053)
There are many cases where you want to access your enum values with a string key, for example, when the key need to be calculated based on some constraints:
const getEditor = (needMouse?: boolean): string => {
return needMouse ? 'VSCode' : 'Vim';
}
const editor = Editor[getEditor(true).toUpperCase()];
Or when you want to map your enum to some other data structures, and still want to refer to that enum values:
const editorList = Object.keys(Editor)
.filter(key => key !== 'EMACS')
.map(key => ({
editorCode: key,
displayName: Editor[key]
}));
// Expected an array of:
// [
// {
// editorCode: 'VIM',
// displayName: 'Neovim'
// },
// {
// editorCode: 'VSCODE',
// displayName: 'Visual Studio Code'
// }
// ]
The values of the Editor enum can only be accessed by some keys of the union type “VIM” | “EMACS” | “VSCODE”. To make the above two example works, we need to annotate the key variable as the union “VIM” | “EMACS” | “VSCODE”.
You can define this union in two ways:
type EditorKey = "VIM" | "EMACS" | "VSCODE";
// or
type EditorKey = keyof typeof Editor;
Now we can use type assertion to convince TypeScript that key is a value of type EditorKey, and it should be OK to compile your code:
const editorList = Object.keys(Editor)
.filter(key => key !== 'EMACS')
.map(key => ({
editorCode: key,
displayName: Editor[key as EditorKey] // THIS!
}));