避免任何类型在打字稿中获取枚举值

rus*_*Bay 1 typescript

我需要循环遍历枚举类型来填充反应组件中的一些选项。在下面找到枚举以及从中返回键和值的函数。

export enum ProyectType {
  time, 
  hits, 
  value, 
  results
}

function projectTypeValues() {
  const values = Object.keys(ProyectType).filter(k => typeof ProyectType[k as any] === "number"); // ["time", "hits", "value", "results"]
  const keys = values.map(k => ProyectType[k as any]); // [0, 1, 2, 3]
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢any其中的类型,ProyectType[k as any]所以我尝试了:

type EnumIndex = number | string;
ProyectType[k as EnumIndex]
Run Code Online (Sandbox Code Playgroud)

但我得到:Element implicitly has an 'any' type because index expression is not of type 'number'.ts(7015)

我认为索引器可以是数字或字符串类型,因为它Object.Keys是一个包含 8 个元素的数组:["0","1","2","3","time","hits","value","results"]但这两种方法都不起作用。

any如果枚举类型已知,如何在这种情况下删除该类型?

jca*_*alz 5

这里的主要问题是 的类型签名的Object.keys(obj)返回类型为 asstring[]而不是类似 的类型Array<keyof typeof obj>

这是故意的:TypeScript 中的对象类型是开放的,而不是封闭的;它们必须具有一些已知属性,但它们可能具有其他属性。请参阅问答对“为什么 Object.keys 在 TypeScript 中不返回 keyof 类型?” 更多细节。

ProyectType因此,编译器看到您尝试使用任意索引进行索引string,并且对此不满意。如果您不关心额外键的可能性,或者您碰巧知道键是什么,则可以使用类型断言来告诉编译器它无法弄清楚什么。

例如,您可以这样做:

type ProyectTypeKeys = Array<keyof typeof ProyectType | number>;
// type ProyectTypeKeys = (number | "time" | "hits" | "value" | "results")[]

const values = (Object.keys(ProyectType) as ProyectTypeKeys).
    filter((k): k is keyof typeof ProyectType =>
        typeof ProyectType[k] === "number");
// const values: ("time" | "hits" | "value" | "results")[]

const keys = values.map(k => ProyectType[k]);
// const keys: ProyectType[]
Run Code Online (Sandbox Code Playgroud)

在这里,我定义ProyectTypeKeys为一个数组类型,其元素要么是枚举对象的已知字符串键,要么number...这是您期望看到的内容,也是您执行此filter()步骤的原因。

同样,我已将回调注释filter()用户定义的类型保护函数,以便编译器使用调用签名将filter()filter()完整数组类型的输出类型缩小ProyectTypeKeys到仅输出的类型:keyof typeof ProyectType,又名"time" | "hits" | "value" | "results"

之后,根据需要推断 的类型keysProyectType[]

Playground 代码链接