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

Posted

技术标签:

【中文标题】避免任何类型在打字稿中获取枚举值【英文标题】:Avoid any type getting enum values in typescript 【发布时间】:2021-07-08 22:47:24 【问题描述】:

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

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]

我不喜欢ProyectType[k as any] 中的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 类型?

【问题讨论】:

您不能改用这些解决方案吗? ***.com/questions/43100718/… 【参考方案1】:

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

这是有意的:TypeScript 中的对象类型是open 而不是close;他们必须有一些已知的属性,但他们可能额外的属性。有关详细信息,请参阅 Q/A 对 "Why doesn't Object.keys return a keyof type in TypeScript?"。

所以编译器看到你试图用任意的string 索引到ProyectType,并且对此不满意。如果您不关心额外密钥的可能性,或者如果您碰巧知道密钥是什么,您可以使用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... 这是您希望看到的,也是您这样做的原因 @987654335 @步骤。

同样,我已将 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

【讨论】:

【参考方案2】:

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

看看这个方法:

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

【讨论】:

我尽量避免任何未知,并且接受的答案方法似乎更正确((k): k is keyof typeof ProyectType)。那是我一直在寻找的,但是您的也是有用的 sn-p,谢谢您的回答。【参考方案3】:

使用类型断言

这是一种优雅的替代方式;)考虑到enums 只能包含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。然后我映射它们以将字符串转换为您所写的数字。

【讨论】:

我尽量避免使用anyunknow,但这是一个有用的sn-p,感谢您的回答

以上是关于避免任何类型在打字稿中获取枚举值的主要内容,如果未能解决你的问题,请参考以下文章

使用枚举和泛型在打字稿中获取星期几

在打字稿中扩展枚举

字符串枚举类似于打字稿中的类型[重复]

打字稿:如何检查一个值是不是是有效的枚举键值? [复制]

如何在打字稿中键入枚举变量?

通用类型(T)与打字稿中的任何类型有啥区别