【问题标题】:How to properly type an array of enum entries?如何正确键入枚举条目数组?
【发布时间】:2021-09-03 06:07:27
【问题描述】:

我在下面有一个基本的enum

export enum Fruit {
   apple,
   banana
}

我想导出一个固定的Array enumkeys

export const Fruits = Object.entries(Fruit).map(f => f[0]);

应根据需要将['apple', 'banana']Fruits 键入string[]

为了尝试更具体的打字,我添加了as keyof typeof Fruit,就像这样

 export const Fruits = Object.entries(Fruit).map(f => f[0] as keyof typeof Fruit);

这给了我 type const Fruits: ("apple" | "banana")[]这是我能得到的最多的吗?

我的目标是获得像const Fruits: ["apple", "banana"] = .... 这样的打字,我认为这是我应该制作的完美打字

脚注:

我不想使用定义enums 的其他方法,只是为了避免冗余,

export enum Fruit {
   apple = 'apple',
   banana = 'banana'
}

我很乐意做这样的事情:

interface Meal {
   fruit: keyof tpeof Fruit // since the default enum values are integers, use keys
}

所以我很高兴有一个不需要我这样做的解决方案。如果没有其他办法,请在回答中提及。

【问题讨论】:

    标签: typescript enums typing


    【解决方案1】:

    请记住,不能保证Object.entriesObject.keys 保留键的顺序。因此,您需要返回所有可能状态的排列,而不仅仅是 ['apple', 'banana']

    在这种情况下,它应该是['apple', 'banana'] | ['banana', 'apple']

    export enum Fruit {
        apple,
        banana
    }
    
    // credits goes to https://twitter.com/WrocTypeScript/status/1306296710407352321
    type TupleUnion<U extends PropertyKey, R extends any[] = []> = {
        [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
    }[U];
    
    const keys = <
        Keys extends string,
        Obj extends Record<Keys, unknown>
    >(obj: Obj) =>
        Object.keys(Fruit) as TupleUnion<keyof Obj>;
    
    const result = keys(Fruit)
    
    // ["apple", "banana"] | ["banana", "apple"]
    type Check = typeof result
    

    Playground 我使用了keys 而不是entries,因为我们只对键感兴趣。

    Here,在我的博客中,您可以找到更多关于将联合转换为元组和function arguments inference

    那么,哪个枚举更好:值是整数还是字符串?

    首先,枚举有其自身的缺陷。 考虑这个例子:

    export enum Fruit {
        apple,
        banana
    }
    const fruit = (enm: Fruit) => {}
    
    fruit(100) // ok, no error
    

    安全吗?不!

    如果你有位掩码,就必须使用整数枚举。

    最好使用带有字符串值的枚举:

    export enum Fruit {
       apple = 'apple',
       banana = 'banana'
    }
    

    如果您仍想将枚举与整数一起使用,请考虑以下示例:

    const enum Fruit {
        apple,
        banana,
    }
    
    const fruit = (enm: typeof Fruit) => { }
    
    fruit(100) // expected error
    
    Object.keys(Fruit) // impossible
    

    如果您想将枚举与整数和Object.keys/entries 一起使用,您可能需要使用最安全的 方法:

    export const Fruit = {
        apple: 0,
        banana: 1,
    } as const
    
    const fruit = (enm: typeof Fruit) => { }
    
    fruit(100) // expected safe
    
    

    【讨论】:

    • 所以我已经拥有的const Fruits: ("apple" | "banana")[] 将涵盖键顺序的问题,对吧?我们在该类型上唯一没有的是它并没有严格地说所有键都在数组中。
    • 不完全是,因为("apple" | "banana")[] 可能有重复:['apple','apple','banana'] - 这不是我们想要的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    相关资源
    最近更新 更多