这里如何处理这个错误?我可以限制递归深度,或者只告诉TS它是好的吗?

export type StateUnion<T> = T extends { states: Record<infer K, any> }
  ? K | StateUnion<T['states'][K]>
  : never;

Playground

推荐答案

当你有一个像StateUnion这样的recursive conditional type,并将它应用于一个本身是递归的类型,比如Config,你很容易陷入编译器抱怨递归深度的情况.有时,您可以调整其中一个或两个定义来回避问题,但这些方法往往是反复试验的(至少在我的经验中是这样).

您可以try 的一种方法是为递归条件类型提供显式深度限制机制, Select 一个合理的默认最大深度,但允许用户更改它.对于你的StateUnion人来说,它可能是这样的:

type StateUnion<T, D extends number = 8, A extends any[] = []> =
  A['length'] extends D ? never : (
    T extends { states: Record<infer K, any> }
    ? K | StateUnion<T['states'][K], D, [0, ...A]>
    : never);

这里的预期用途是StateUnion<T, D>,其中D是对应于所需最大深度的数字literal type.如果您写入StateUnion<T>而不指定D,则最大深度为8(但您可以更改该值).

不幸的是,TypeScrip(从5.1版开始)不知道如何在类型级别直接计算数学,所以我不能轻易地说出StateUnion<T['states'][K], D-1>这样的东西.相反,我求助于使用tuple typesvariadic tuple types来操作这些类型,其中tuple types具有已知的数字文字length属性.因此,不是常规的"如果Depth为0,则退出,否则将Depth减go 1并递归",我必须说类似于"如果此数组的长度与最大深度相同,则Bal out,否则将一个元素附加到数组并递归".所以我在那里有累加器数组A,我们正在判断A["length"],并将[0, ...A]作为新A传入.

让我们来测试一下:

interface Test {
  states: { a: { states: { b: { states: { c: {
    states: { d: { states: { e: Test } } } 
  } } } } } }
}

type SU2 = StateUnion<Test, 2>
//type SU2 = "a" | "b"
type SU4 = StateUnion<Test, 4>
//type SU4 = "a" | "b" | "c" | "d"
type SU8 = StateUnion<Test> // defaults to 8
// type SU8 = "a" | "b" | "c" | "d" | "e"

它按预期工作,如果我做了更改,那么您的原始代码StateUnion<Config>(或StateUnion<T>,其中T extends Config)编译时不会出错.

Playground link to code

Typescript相关问答推荐

具有继承的基于类的react 组件:呈现不能分配给基类型中的相同属性

已解决:如何使用值类型限制泛型键?

一个打字类型可以实现一个接口吗?

FatalError:Error TS6046:';--模块分辨率';选项的参数必须是:'; node ';,'; node 16';,'; node

Angular material 无法显示通过API获取的数据

Typescript 中相同类型的不同结果

TS2739将接口类型变量赋值给具体变量

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

三重融合视角与正交阵

如何在TypeScrip中使用数组作为字符串的封闭列表?

如何使对象同时具有隐式和显式类型

如何在TypeScript中将元组与泛型一起使用?

如何在Vuetify 3中导入TypeScript类型?

为什么 TypeScript 类型条件会影响其分支的结果?

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

Next.JS-13(应用程序路由)中发现无效的中间件

从函数参数推断函数返回类型

基于每个数组元素的动态类型

Supabase 连接返回 1 个对象而不是对象列表

React:如何在子组件中使用前向引用中的数据