【问题标题】:TypeScript mapping enumTypeScript 映射枚举
【发布时间】:2018-02-24 13:33:08
【问题描述】:

在我的应用程序中,我们混合使用模拟和真实 REST 数据。在 TypeScript 中,为了方便起见,我定义了一大堆枚举。

当我使用数据创建任何类型的模拟数组时,我使用以下限制:

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

TypeScript 有效地将其解析为数字:

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

但是,在我的 REST API 中,我收到了与其字符串表示形式相同的一组枚举。两种方式都可以通过以下方式进行转换:

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

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

是否可以生成以优雅方式处理此转换的通用类,类似于 Stack 社区在 THIS question 中建议我的方式

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以创建一个类似于对象的函数:

    // 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
    

    【讨论】:

    • 嗯...这绝对不相似 ;) 就像一个魅力。我有疑问,[keyof T] 部分代表什么?除此之外,我看到keyof 是一个...解决问题的关键。再次感谢您!
    【解决方案2】:

    除了来自 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))
    

    唯一仍然困扰我的是事实,如果要分配泛型类型,TypeScript 就会发疯:

    fromValueToString<MyEnum>(MyEnum, 'VAL_ONE')
    

    不过,这只是对原始答案的补充。

    【讨论】:

    • 尝试 fromValueToString(MyEnum, 'VAL_ONE')
    • 是的,但这不会给我们带来更多的类型安全性,因为typeof(AnyEnum) 只是一个对象,对吗?
    • 不,这不是真的,但你想要什么额外的安全,也许我们可以实现它:)
    • 好吧,我假设验证参数value 的正确性在技术上是不可能的(即验证string 实际上是keyof MyEnum 或数字在枚举集中确实有匹配对)。只是有点令人困惑,TypeScript 不会将枚举视为具有专用类型的类,而不是普通对象......无论如何,它仍然很酷:)
    【解决方案3】:

    string literals 代替枚举怎么样?

    我猜您正在使用 enums 来避免拼写错误,并且您希望 TypeScript 为您“捕捉”它。因此,如果您使用string literals,您是类型安全,您将使用相同的“语言”与服务器交谈

    例如:

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

    【讨论】:

    • 恐怕这种简单的转换是不可能的,因为我们在另一个主要用例中使用它们,数组索引。在这种情况下,将它们更改为字符串文字(总的来说,我同意,从简单的角度来看,这将是有益的)将使我们的生活更加艰难
    【解决方案4】:

    使用ts-enum-utilgithubnpm),您可以通过运行时验证在枚举值和名称之间(在任一方向)执行类型安全的转换。如果在运行时遇到无效值,您可以选择抛出错误或返回默认值(默认未定义)的方法变体。

    例子:

    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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      • 2017-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      相关资源
      最近更新 更多