到目前为止你所说的(需要接受所有字符串/数字/异构枚举),我能做的最接近的是这样的:
type Enum<E> = Record<keyof E, number | string> & { [k: number]: string };
function acceptEnum<E extends Enum<E>>(
myEnum: E
): void {
// do something with myEnum... what's your use case anyway?
}
enum E { X, Y, Z };
acceptEnum(E); // works
如果您只知道myEnum 是“某种枚举类型”,我不确定您要做什么,但我想这取决于您自己想办法。
我是如何想到这个的:我检查了一堆具体的enum 类型,它们似乎具有带有字符串键和字符串或数值(前向映射)的属性,以及带有字符串的数字索引键值(数值的反向映射)。
const works: { X: 0, Y: 1, Z: 2, [k: number]: string } = E; // works
语言设计者可能进一步限制了这一点,因为反向映射只会产生在正向映射中看到的特定数字键和字符串值,但由于某种原因,它没有这样实现:
const doesntWork: { X: 0, Y: 1, Z: 2, [k: number]: 'X' | 'Y' | 'Z' } = E; // error
const alsoDoesntWork: { X: 0, Y: 1, Z: 2, 0: 'X', 1: 'Y', 2: 'Z' } = E; // error
所以我可以对枚举类型施加的最严格的约束是上面的E extends Enum<E>。
请注意,此代码不适用于 const enum 在运行时不存在的类型:
const enum F {U, V, W};
acceptEnum(F); // nope, can't refer to `F` by itself
还要注意,上述类型 (E extends Enum<E>) 允许一些它可能不应该做的事情:
acceptEnum({ foo: 1 }); // works
在上面,{foo: 1} 似乎是一个类似于enum Foo {foo = 1} 的数字枚举,但它没有反向映射,如果你依赖它,事情会在运行时爆炸。请注意,{foo: 1} 似乎没有索引签名,但它仍然匹配索引签名implicitly。除非您添加了一些明确的错误值,否则它不会不匹配:
acceptEnum({foo: 1, 2: 3}); // error, prop '2' not compatible with index signature
但是这里没有什么可做的。正如我上面提到的,enum 键入的实现目前并没有尽可能多地限制数字键,因此在编译时似乎没有办法区分具有良好反向映射的枚举和没有的枚举。
希望对您有所帮助。祝你好运!