如何在 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<43>
,但不适用于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的主要内容,如果未能解决你的问题,请参考以下文章