【问题标题】:Casting integer value to String Enum in typescript returns undefined在打字稿中将整数值转换为字符串枚举返回未定义
【发布时间】:2021-09-09 06:56:41
【问题描述】:

我的 API 返回字符串枚举。所以我已经注册了我的枚举。

export enum MyEnum {
    Unknown = 'Unknown',
    SomeValue = 'SomeValue',
    SomeOtherValue = 'SomeOtherValue',
  }

现在我们从另一个无法更改的来源获得一个整数值。这需要在某个时候映射到 MyEnum 并检查一个条件。使用下面的代码应该可以工作,但由于某种原因它返回 undefined。

const myIntValue = 1;
const myEnumValue = MyEnum[myIntValue]; // This returns undefined..

var myCondition = myEnumValue === MyEnum.SomeValue; // Is false because undefined != MyEnum.SomeValue

如何让 typescript 中的 Enum 值转换为正确的枚举值或至少适用于我的条件?

【问题讨论】:

    标签: typescript enums


    【解决方案1】:

    你有两个选择。

    第一个,你可以修改你的enum

    enum MyEnum {
        Unknown = 1,
        SomeValue,
        SomeOtherValue,
    }
    
    const myIntValue = 1;
    const myEnumValue = MyEnum[myIntValue]; // string
    

    如果您从MyEnum 定义中删除1,它将从0 开始。

    我个人不喜欢这个解决方案,因为numerical enum 不是最佳选择。

    考虑这个例子:

    const foo = (en: MyEnum) => 42
    
    foo(99999) // ok
    

    第二个选项。

    您可以使用元组将整数映射到枚举:

    const enum MyEnum {
        Unknown = 'Unknown',
        SomeValue = 'SomeValue',
        SomeOtherValue = 'SomeOtherValue',
    }
    
    const MapEnum = [MyEnum.Unknown, MyEnum.SomeValue, MyEnum.SomeOtherValue] as const;
    
    const result = MapEnum[1] // MyEnum.SomeValue
    

    请记住,enum/object 键是无序的,因此动态创建这样的元组是不安全的。

    更新

    第二个选项有效,虽然它更容易出错...

    enum MyEnum {
        Unknown = 'Unknown',
        SomeValue = 'SomeValue',
        SomeOtherValue = 'SomeOtherValue',
    }
    
    type TupleUnion<U extends string, R extends any[] = []> = {
        [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
    }[U];
    
    const MapEnum: TupleUnion<MyEnum> = [MyEnum.Unknown, MyEnum.SomeValue, MyEnum.SomeOtherValue,];
    

    你不会忘记一些价值

    没有排列的替代方式:

    enum MyEnum {
        Unknown = 'Unknown',
        SomeValue = 'SomeValue',
        SomeOtherValue = 'SomeOtherValue',
    }
    
    // credits goes to https://stackoverflow.com/a/50375286
    type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
        k: infer I
    ) => void
        ? I
        : never;
    
    // Credits goes to https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
    type UnionToOvlds<U> = UnionToIntersection<
        U extends any ? (f: U) => void : never
    >;
    
    type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;
    
    type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
    
    type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
        ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
        : [T, ...A];
    
    type Result = UnionToArray<MyEnum>
    
    const MapEnum: UnionToArray<MyEnum> = [MyEnum.Unknown, MyEnum.SomeValue, MyEnum.SomeOtherValue,];
    
    

    您可以在我的blog 中找到更多示例

    【讨论】:

    • 第一个选项不是一个选项,因为主 API 仍然返回的字符串。所以字符串枚举要求更重要。第二个选项有效,尽管如果忘记更新枚举和映射更容易出错。谢谢!
    • 打字稿文档确实声明字符串枚举将从零开始自动递增,所以我觉得很奇怪,我无法根据 int 将其转换为正确的值。
    猜你喜欢
    • 2019-10-30
    • 2018-11-09
    • 2018-07-05
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 2022-06-11
    相关资源
    最近更新 更多