字符串枚举的反向映射

Reverse-Mapping for String Enums

我想在打字稿中使用字符串枚举,但我看不到它支持反向映射。 我有一个这样的枚举:

enum Mode {
    Silent = "Silent",
    Normal = "Normal",
    Deleted = "Deleted"
}

我需要这样使用它:

let modeStr: string;
let mode: Mode = Mode[modeStr];

是的,我不知道 modeStr 字符串中有什么,我需要将其解析为枚举,或者如果枚举定义中未显示该字符串,则在运行时解析失败。 我怎样才能做到尽可能整洁? 提前致谢

我们可以让Mode成为一个类型和一个相同类型的值。

type Mode = string;
let Mode = {
    Silent: "Silent",
    Normal: "Normal",
    Deleted: "Deleted"
}

let modeStr: string = "Silent";
let mode: Mode;

mode = Mode[modeStr]; // Silent
mode = Mode.Normal; // Normal
mode = "Deleted"; // Deleted
mode = Mode["unknown"]; // undefined
mode = "invalid"; // "invalid"

更严格的版本:

type Mode = "Silent" | "Normal" | "Deleted";
const Mode = {
    get Silent(): Mode { return "Silent"; },
    get Normal(): Mode { return "Normal"; },
    get Deleted(): Mode { return "Deleted"; }
}

let modeStr: string = "Silent";
let mode: Mode;

mode = Mode[modeStr]; // Silent
mode = Mode.Normal; // Normal
mode = "Deleted"; // Deleted
mode = Mode["unknown"]; // undefined
//mode = "invalid"; // Error

字符串枚举为 :

enum Mode {
    Silent = <any>"Silent",
    Normal = <any>"Normal",
    Deleted = <any>"Deleted"
}

let modeStr: string = "Silent";
let mode: Mode;

mode = Mode[modeStr]; // Silent
mode = Mode.Normal; // Normal
//mode = "Deleted"; // Error
mode = Mode["unknown"]; // undefined

如果您可以使用代理,我制作了一个更通用和紧凑的版本:

stringEnum.ts

export type StringEnum<T extends string> = {[K in T]: K}
const proxy = new Proxy({}, {
  get(target, property) {
    return property;
  }
})
export default function stringEnum<T extends string>(): StringEnum<T> {
  return proxy as StringEnum<T>;
}

用法:

import stringEnum from './stringEnum';
type Mode = "Silent" | "Normal" | "Deleted";
const Mode = stringEnum<Mode>();

到目前为止我发现的最干净的方法是制作辅助地图:

let reverseMode = new Map<string, Mode>();
Object.keys(Mode).forEach((mode: Mode) => {
    const modeValue: string = Mode[<any>mode];
    reverseMode.set(modeValue, mode);
});

这样你就可以let mode: Mode = reverseMode.get('Silent');

优点:无需重复值,提供枚举枚举的方法,让 TSLint 开心...

编辑:我最初写 Mode[mode] 但后来 TS 可能会在这一行抛出错误 TS7015,所以我添加了强制转换。

None 的答案确实对我有用,所以我必须恢复正常才能进行循环。 我的枚举是

enum SOME_CONST{
      STRING1='value1', 
      STRING2 ='value2',
      .....and so on
}


getKeyFromValue =(value:string)=> Object.entries(SOME_CONST).filter((item)=>item[1]===value)[0][0];

此回答来自@PhiLho,

我没有足够的代表来评论他的消息。

let reverseMode = new Map<string, Mode>();
Object.keys(Mode).forEach((mode: Mode) => {
    const modeValue: string = Mode[<any>mode];
    reverseMode.set(modeValue, mode);
});

但是,.set 的第一个参数应该是键,第二个应该是值。

reverseMode.set(modeValue, mode);

应该...

reverseMode.set(mode, modeValue);

导致这个...

let reverseMode = new Map<string, ErrorMessage>();
Object.keys(ErrorMessage).forEach((mode: ErrorMessage) => {
    const modeValue: string = ErrorMessage[<any>mode];
    reverseMode.set(mode, modeValue);
});

@PhiLho 可能错过这个的原因是因为 OP 提供的原始对象的键和值是相同的。

对于仍在为此苦苦挣扎的所有人来说,这是完成此任务的一种快速而肮脏的方法。

enum Mode {
    Silent = "Silent",
    Normal = "Normal",
    Deleted = "Deleted"
}

const currMode = 'Silent',
  modeKey = Object.keys(Mode)[(Object.values(Mode) as string[]).indexOf(currMode)];

但是,您应该注意一些注意事项!

Microsoft 将 Git 错误标记为“按预期工作”的最可能原因可能是因为它处理字符串文字,而枚举最初设计为可索引。虽然上面的代码可以使用 TSLint 进行检查,但它有两个问题。对象在转换为数组时不能保证保留预期的顺序,我们正在处理可能唯一也可能不唯一的字符串文字。

看看这个 StackBlitz,其中有两个值为 'Silent' 的模式。您零保证一旦查找完成,它不会 return 'Ignore' 超过 'Silent'。

https://stackblitz.com/edit/typescript-hyndj1?file=index.ts

标准类型实现此功能 - 只需检查未定义并处理。

type Mode = "Silent" | "Normal" | "Deleted";
const a = Mode["something else"];
//a will be undefined

此外,您可以在上面添加记录类型以扩展“枚举”,比如将一个简短的枚举键转换为更详细的输出(https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type):

const VerboseMode: Record<Mode, string> = {
  Silent: "Silent mode",
  Normal: "Normal mode",
  Deleted: "This thing has been deleted"
}