如何正确键入枚举条目数组?

How to properly type an array of enum entries?

我有一个基本的enum如下:

export enum Fruit {
   apple,
   banana
}

我想导出 enum keys

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

应该根据需要给出 ['apple', 'banana']Fruits typed as string[].

为了尝试更具体的 键入 ,我添加了 as keyof typeof Fruit 这样的

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

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

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

脚注:

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

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

我很乐意做这样的事情:

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

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

请记住,不能保证 Object.entriesObject.keys 保留键的顺序。因此,您需要 return 所有可能状态的排列,而不仅仅是 ['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, in my blog, you can find more about convertiong union to tuples and 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