NodeJS 字符串枚举的反向Map

1l5u6lss  于 2023-05-28  发布在  Node.js
关注(0)|答案(7)|浏览(185)

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

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

我需要这样使用它:

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

是的,我不知道它在modeStr字符串中是什么,我需要它解析为枚举,或者如果字符串没有在枚举定义中出现,则在运行时解析失败。我怎样才能做到最好?先谢了

bvjveswy

bvjveswy1#

我们可以将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

String Enum作为此答案:

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
xxls0lw8

xxls0lw82#

到目前为止,我发现的最干净的方法是制作一个二级Map:

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

因此,您可以执行let mode: Mode = reverseMode.get('Silent');
优点:不需要重复值,提供了枚举枚举的方法,保持TSLint愉快...
编辑:我最初写的是Mode[mode],但是TS可能会在这一行抛出错误TS7015,所以我添加了强制转换。

bfnvny8b

bfnvny8b3#

如果你可以使用代理,我做了一个更通用和紧凑的版本:
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>();
uajslkp6

uajslkp64#

这个答案来自@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提供的原始对象的键和值是相同的。

nx7onnlm

nx7onnlm5#

没有一个答案真的对我有用,所以我必须回到正常的循环。我的enum是

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

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

swvgeqrz6#

标准类型实现了这个功能--只需要检查undefined和handle即可。

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"
}
mtb9vblg

mtb9vblg7#

对于所有仍在为此挣扎的人来说,这是一种快速而肮脏的方式。

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

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

但是,有一些警告,你应该知道!
微软将Git bug标记为“按预期工作”的最可能原因可能是因为这涉及字符串字面量,而枚举最初被设计为可索引的。虽然上面的代码可以使用TSLint运行,但它有两个问题。对象不能保证在转换为Array时保持预期的顺序,我们正在处理可能是唯一的或可能不是唯一的字符串。
看看这个StackBlitz,其中有两个值为“Silent”的Mode。你没有任何保证,它不会返回'忽略'超过'沉默'一旦查找完成。
https://stackblitz.com/edit/typescript-hyndj1?file=index.ts

相关问题