简体   繁体   English

TypeScript映射枚举

[英]TypeScript mapping enum

In my application we work on mix of mocks and real REST data. 在我的应用程序中,我们致力于模拟和真实REST数据的混合。 In TypeScript i have whole bunch of enumse defined for convenience. 在TypeScript中,为方便起见,我定义了一堆枚举。

When I create any kind of mock array with data, I use following constriction: 当我用数据创建任何一种模拟数组时,我使用以下约束:

enum MyEnum { 'myEnumValue1' = 0, myEnumValue2 } 
(...)
 enumField: MyEnum.myEnumValue1,
(...)

which is effectively resolved by TypeScript to number: TypeScript有效地解决了以下问题:

(...)
enumField: 1,
(...)

However, form my REST API I'm receiving same set of enums as their string representation. 但是,通过我的REST API,我将收到与它们的字符串表示形式相同的枚举集。 Conversion in both way is possible via: 可以通过以下两种方式进行转换:

MyEnum['string'] => number
MyEnum[number] => string

MyEnum['myEnumValue1'] => 0
MyEnum[0] => 'myEnumValue1'

Is it possible to generate generic class that will handle this conversion in graceful way, similar to how Stack Community suggested me in THIS question 是否可以生成通用类来以优美的方式处理此转换,类似于Stack Community在此问题中向我提出的建议

You can create a function similar to the one for objects: 您可以创建类似于对象的函数:

// Return type is a bit more tricky because we have to get the enum type from typeof enum
function fromValue<T>(o: T, value: string): { [P in keyof T]: T[P]  }[keyof T]{
    return  (o as any)[value]; // No type safety here unfrotunately
}

var value = fromValue(MyEnum, ""); //value will be of type MyEnum

Beside perfect answer from Titan, here is a little tweak to work both ways regarding what type of value you wish to map from/to (string or number) and what unified result you wish (string or number): 除了Titan的完美答案外,这还需要一些调整,以两种方式来处理您希望从/映射到什么类型的值(字符串或数字)以及想要什么统一的结果(字符串或数字):

enum MyEnum {
    'VAL_ONE' = 0,
    'VAL_TWO' = 1
}

function fromValuetoNumber<T>(o: T, value: string | number): {[P in keyof T]: T[P]} {
    if (typeof (value) === 'string') {
        return  (o as T)[value]; 
    } else if (typeof (value) === 'number') {
        return (o as T)[o[value]]
    }   
}

function fromValueToString<T>(o: T, value: string | number): {[P in keyof T]: T[P]} {
    if (typeof (value) === 'string') {
        return  (o as T)[o[value]]; 
    } else if (typeof (value) === 'number') {
        return (o as T)[value]
    }   
}

console.log(fromValuetoNumber(MyEnum, 'VAL_ONE'))
console.log(fromValuetoNumber(MyEnum, 0))

console.log(fromValueToString(MyEnum, 'VAL_ONE'))
console.log(fromValueToString(MyEnum, 0))

Only thing that still bothers me is fact, that if generic type will be assigned, TypeScript goes crazy: 唯一令我困扰的是事实,即如果将泛型分配,TypeScript就会发疯:

fromValueToString<MyEnum>(MyEnum, 'VAL_ONE')

Still, this is just an addition to original answer. 不过,这只是原始答案的补充。

How about using string literals instead of enums? 如何使用string literals而不是枚举?

I'm guessing that you are using the enums to avoid typos, and you want TypeScript to "catch" it for you. 我猜您正在使用enums来避免输入错误,并且您希望TypeScript为您“捕获”它。 So if you use string literals , you are type safe and you will talk to the server in the same "language" 因此,如果您使用string literals ,则可以安全输入,并且将使用相同的“语言”与服务器对话

For example: 例如:

export type Sex = 'male' | 'female';
var sex: Sex = 'mela'; // Typo => ERROR from typescript

Using ts-enum-util ( github , npm ), you can perform type-safe conversions between enum values and names (in either direction) with run-time validation. 使用ts-enum-utilgithubnpm ),您可以通过运行时验证在枚举值和名称(沿任一方向)之间执行类型安全的转换。 You can choose between variations of method that either throw an error or return a default value (undefined by default) if an invalid value is encountered at run time. 如果在运行时遇到无效值,则可以选择引发错误或返回默认值(默认情况下未定义)的方法变体。

Example: 例:

import {$enum} from "ts-enum-util";

enum MyEnum {
    FOO = 0,
    BAR = 1
}

function getMyEnum1(apiString: string): MyEnum {
    // throws informative error if "apiString" is not 
    // "FOO" or "BAR"
    return $enum(MyEnum).getValueOrThrow(apiString);
}

function getMyEnum2(apiString: string): MyEnum {
    // returns MyEnum.FOO if "apiString" is not 
    // "FOO" or "BAR"
    return $enum(MyEnum).getValueOrDefault(apiString, MyEnum.FOO);
}

function getMyEnum3(apiString: string): MyEnum | undefined {
    // returns undefined if "apiString" is not 
    // "FOO" or "BAR"
    return $enum(MyEnum).getValueOrDefault(apiString);
}

// type: ("FOO" | "BAR")
// value: "BAR"
const enumName = $enum(MyEnum).getKeyOrThrow(1);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM