簡體   English   中英

在 TypeScript 中獲取帶有值字符串(反向映射)的枚舉鍵

[英]Getting the enum key with the value string (reverse mapping) in TypeScript

我有一個枚舉:

export enum ApiMessages {
    logged_ok = 'Logged OK',
    register_ok = 'Register OK'
}

我有一個以枚舉為參數的函數:

export function responseOK(message: ApiMessages, result ?: any): ApiResponse {
    return {
        "status": "ok",
        "code": 200,
        "messageId": ApiMessages[message], <-- KO TS7015
        "message": message,
        "result": result
    };
}

我這樣調用函數:

responseOK(ApiMessages.logged_ok, {user: userRes})

我正在嘗試將枚舉鍵和枚舉字符串值返回給響應,但出現 TS 錯誤:

TS7015:元素隱式具有“任何”類型,因為索引表達式不是“數字”類型。

我有嚴格的 TypeScript 配置。 添加 suppressImplicitAnyIndexErrors 不是一個選項。

打字稿版本:2.9.2

手冊中所述:

請記住,字符串枚舉成員根本不會生成反向映射。

這意味着在您的情況下沒有簡單的反向映射。

解決方法:獲取字符串枚舉成員的反向映射

要通過值獲取枚舉成員的鍵,您必須遍歷枚舉鍵並將關聯的值與目標值進行比較。

function getEnumKeyByEnumValue(myEnum, enumValue) {
    let keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue);
    return keys.length > 0 ? keys[0] : null;
}

您可以更嚴格地按如下方式鍵入(請注意,我們可以將enum解釋為可索引類型,此處的鍵和值都是字符串):

function getEnumKeyByEnumValue<T extends {[index:string]:string}>(myEnum:T, enumValue:string):keyof T|null {
    let keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue);
    return keys.length > 0 ? keys[0] : null;
}

下面是一些演示代碼。 您還可以在 TypeScript Playground 上看到它的實際效果

enum ApiMessages {
    logged_ok = 'Logged OK',
    register_ok = 'Register OK'
}

let exampleValue = ApiMessages.logged_ok;
let exampleKey = getEnumKeyByEnumValue(ApiMessages, exampleValue);

alert(`The value '${exampleValue}' has the key '${exampleKey}'`)

function getEnumKeyByEnumValue<T extends {[index:string]:string}>(myEnum:T, enumValue:string):keyof T|null {
    let keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue);
    return keys.length > 0 ? keys[0] : null;
}

將此添加到您的responseOK()中,您最終會得到:

function responseOK(message: ApiMessages, result ?: any) {
    return {
        "status": "ok",
        "code": 200,
        "messageId": getEnumKeyByEnumValue(ApiMessages, message),
        "message": message,
        "result": result
    };
}

您可以輕松地創建一個映射,該映射允許您從值中獲取鍵,而無需為其創建特殊函數。

export enum ApiMessage {
    logged_ok = 'Logged OK',
    register_ok = 'Register OK'
}

export type ApiMessageKey = keyof typeof ApiMessage;

export const API_MESSAGE_KEYS = new Map<ApiMessage, ApiMessageKey>(
    Object.entries(ApiMessage).map(([key, value]:[ApiMessageKey, ApiMessage]) => [value, key])
)

API_MESSAGE_KEYS.get(ApiMessage.logged_ok); // 'logged_ok'

對於那些看起來和我一樣的人來說,這對我有用。

注意:這僅在您知道您的字符串值是有效的“鍵”時才有效。

enum Fruit {
    Apple = 'apple',
    Bananna = 'bananna'
}

const str: string = 'apple';

const fruit = str as Fruit;

if (fruit === Fruit.Apple)
    console.log("It's an apple");

if (fruit === Fruit.Bananna)
    console.log("It's a bananna");

您現在可以在 TypeScript 中獲取類型中枚舉的特征及其鍵🎉🎉

 enum ApiMessage {
    logged_ok = 'Logged OK',
    register_ok = 'Register OK'
}

// "logged_ok" | "register_ok"
type ApiMessageTraits = keyof typeof ApiMessage;

// "Logged OK" | "Register OK"
type MessageContents = `${ApiMessage}`;

可悲的是,這依賴於將可枚舉項的鍵轉換為字符串,因此除了字符串之外,您不能擁有任何其他類型的鍵。

編輯:通過使用帶有 TypeScript >=4.1的模板文字大大簡化了第二種方法。

簡化版

枚舉生成一個帶有鍵值對的對象。
您真正需要做的就是找到正確的條目(如果有的話)。

所以,給定的例子

enum ApiMessages {
  Ok = 'OK',
  Forbidden = 'No access for you',
}

const example = ApiMessages.Forbidden;

找到枚舉條目

const match = Object.entries(ApiMessages).find(([key, value]) => value === example);

選擇鑰匙

if (match) {
  const [key] = match;
  console.log(`'${example}' matched key '${key}'.`);
}

// output: 'No access for you' matched key 'Forbidden'.

而已。


在這里找到一個工作示例

您可以在此處使用lodash中的 .findKey 進行單行解決方案:

import { findKey } from 'lodash';

enum SomeType {
  FOO = 'bar',
  BAZ = 'qux'
}

const example = findKey(SomeType, (o) => o === 'bar');
console.log(example);

返回'FOO'

我從 API 收到了枚舉代碼,因此需要一種快速的方法來獲取描述......

在 js 中很容易做到,但在 Typescript 中卻不那么容易!

使用 Soren 的方法作為基礎

export function getEnumKeyByEnumValue<T extends { [index: string]: string }>(
  myEnum: T,
  enumValue: string
): keyof T | null {
  let longDesc: string = 'No Match';

  Object.keys(myEnum).forEach((key) => {
    if (key == enumValue) longDesc = myEnum[key];
  });

  return longDesc;
}

getEnumKeyByEnumValue(BenefitType, appeal.benefit)

使用 lodash 你可以嘗試:

_.keys(ApiMessages)[_.toArray(ApiMessages).indexOf(ApiMessages.logged_ok)]

應該給你'logged_ok'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM