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

时间:2021-04-13 21:04:55

标签: typescript

我需要遍历一个枚举类型来填充 react 组件中的一些选项。 在枚举下面找到返回键和值的函数。

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]
}

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

type EnumIndex = number | string;
ProyectType[k as EnumIndex]

但我得到: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 类型?

3 个答案:

答案 0 :(得分:2)

这里的主要问题是 type signature for Object.keys(obj) 的返回类型为 string[] 而不是类似 Array<keyof typeof obj> 的类型。

这是故意的:TypeScript 中的对象类型是开放而不是封闭;它们必须具有一些已知属性,但它们可能具有附加属性。有关详细信息,请参阅问答对 "Why doesn't Object.keys return a keyof type in TypeScript?"

所以编译器看到你试图用任意的 ProyectType 索引到 string,并且对此不满意。如果您只是不关心额外键的可能性,或者如果您碰巧知道键是什么,您可以使用 type assertion 来告诉编译器它无法弄清楚的内容。

例如,您可以这样做:

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[]

这里我将 ProyectTypeKeys 定义为一个数组类型,它的元素要么是枚举对象的已知字符串键,要么是 number...执行 filter() 步骤。

同样,我将 filter() 回调注释为 user-defined type guard function,以便编译器使用 a call signature for filter()filter() 的输出类型从完整数组类型缩小ProyectTypeKeys 到出现的类型:keyof typeof ProyectType,又名,"time" | "hits" | "value" | "results"

此后,keys 的推断类型为 ProyectType[],根据需要。

Playground link to code

答案 1 :(得分:1)

是的,这真的很奇怪,它似乎只发生在某些函数中。

看看这种方法:

const keys = [];
const values = [];
for(const index in ProyectType){
   //typescript infers string to index const  but here there is no error
  typeof ProyectType[index] === "number" ? values.push(index) : keys.push(index)
 
}

使用您编写代码时不会出错的方式的一种可能解决方案是使用未知类型 + 编号。

const values = Object.keys(ProyectType).filter(k => typeof ProyectType[k as unknown as number] === "number"); // ["time", "hits", "value", "results"]

答案 2 :(得分:1)

使用类型断言

这是一种优雅的替代方式;) 考虑到 enum 只能包含 stringnumber 类型并且您的操作是有意的,您可以使用类型断言来获取您的值和键。类型转换(或断言)是一种告诉编译器你知道你在做什么的方式。您可以在 this link 找到更多信息。

在你的情况下,函数应该是这样的:

function projectTypeValues() {
  const values = Object.values(ProyectType)
                .filter((val) => isNaN(val as number));
  const keys = Object.keys(ProyectType)
              .filter(key => !isNaN(key as unknown as number))
              .map(key => +key);
}

我使用了 key as unknown as number,因为在这种情况下我们的键是 string。然后我将它们映射为您写的将字符串转换为数字。