如何在 Typescript 中使用动态枚举器(上限量词)克服枚举类型上的 TS2589

Posted

技术标签:

【中文标题】如何在 Typescript 中使用动态枚举器(上限量词)克服枚举类型上的 TS2589【英文标题】:How to overcome TS2589 on Enumerate type with dynamic Enumerator (upper limit quantifier number) in Typescript 【发布时间】:2021-04-10 21:29:31 【问题描述】:

查看Is it possible to restrict number to a certain range,我找到了用于创建范围和枚举的类型。

查看What is the type of an enum in Typescript?,我找到了将枚举作为值传递给函数的类型定义。

现在: 我正在编写一个 lil UI/UX 库here at prudencss@github,我的爱好项目。 在这样做的同时,玩耍并尝试正确地做事...... 我试图引入以下机制:

我想创建如下枚举:

export enum EInputInteractionState 
  Default = 0,
  Hover = 1,
  Focus = 2,
  Active = 4,
  Selected = 8,

现在,具有已定义状态的组合状态也是可能的,有时也很有用,例如,某些列表元素可能是:

悬停 已选择 同时。 为了能够将所有数据保存在一个 var/number 中,我将初始键/值定义为 v = 0, 2^n ... (== 0, 1, 2, 4, 8, 16, ...) 这将允许我将每个排列组合状态保存为一个数字,该数字是它的活动定义状态的总和......该数字将始终填补二次数字行之间的空白...... 所以基本上虽然我在 EInputInteractionState 中定义了 5 个状态(= 默认状态,加上 4 个组合状态)并将它们定义为v = 0, 2^n,但总体组合可能值将是象征v = 0, 1, 2, 3, ... n, ... (n * 2 - 1) 的高斯和的行= (n * (n + 1) /2)`。

使用我目前所掌握的知识:

export const gaussianSum = <T extends Enum<T>>(E: T): number => 
  let length = Object.keys(E).filter(v => isNaN(v as unknown)).length;

  return length * (length + 1) / 2 + 1;

现在我想最后简单地将一个 Prop 放入我的 React Components IProps 中:

const permutationCount: number = gaussianSum(EInputInteractionState);

interface IProps 
  icon?: TIcon | TIcon[]
  state?: Enumerate<typeof permutationCount>,

但是,如果我只是简单地输入一个具体的数字,Enumarte 类型就可以很好地工作,但是使用这种情况我会得到 TS2589“类型实例化过深并且可能无限。”

有没有办法解决这个问题???

编辑: 打字稿游乐场在这里: playground

【问题讨论】:

你为什么将EInputInteractionState 作为参数传递给你的函数?您的代码缺少某些类型,因此我无法使其在沙箱中运行。请将最低工作示例发布到typescriptlang.org/play 无论如何,虽然我了解您提出的组合状态计算的工作原理,但我不明白您为什么要这样做。似乎不必要的抽象和矫枉过正,除非您的全部目的是使用这样的系统,否则请考虑不同的方法。 我在编辑@jered 中添加了操场 :) 您的问题在EnumerateInternal 类型中。你应该在某些条件下包装你的递归。 【参考方案1】:

例如,您可以先更新您的 EnumerateInternal 类型:

type EnumerateInternal<A extends Array<unknown>, N extends number> = N extends A['length'] ? A : EnumerateInternal<PrependNextNum<A>, N>

但可能并非如此。

您的 Enumerate 类型实用程序应该只接受文字数字。

例如,如果你写:

type Result = Enumerate<10>

它会起作用的。

它也适用于Enumerate&lt;43&gt;,但不适用于44

但为什么只到 43?

因为它会产生从0到42的数字(生命的意义)

所以 TS 有一些递归限制。

如果你想使用返回类型的函数,你不应该写:

Enumerate<typeof gaussianSum>

相反,你应该写:

Enumerate<ReturnType<typeof gaussianSum>>

附:使用Number.isNaN 比使用isNaN 更安全

【讨论】:

第一:感谢 Number.isNaN 提示!!!第二:开个玩笑!哈哈 Main:感谢 Typescript 具有递归限制的提示。在我将此答案标记为已接受之前,如果有人提出某些问题,我会等待:) 请注意,我不是编写这些类型定义的 TS Guru,它们来自问题开头提到的 ***-questions .我想我自己被困住了:) @Joehannes 当然,没问题))也许 smbd 提出了更好的解释和解决方案。也很乐意阅读它

以上是关于如何在 Typescript 中使用动态枚举器(上限量词)克服枚举类型上的 TS2589的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中创建自定义类型

typescript 枚举

如何使用 TypeScript 枚举值作为类型?

如何使用 TypeScript 键入枚举值?

如何在 TypeScript 中合并两个枚举

如何比较 TypeScript 中的枚举