gpt4 book ai didi

typescript - 在函数中使用递归类型时出错

转载 作者:行者123 更新时间:2023-12-04 14:46:06 26 4
gpt4 key购买 nike

我有一个递归类型,它从嵌套对象中提取索引并将它们放在一个扁平的强类型元组中,如下所示:

type NestedRecord = Record<string, any>

type RecursiveGetIndex<
TRecord extends NestedRecord,
TPreviousIndices extends any[] = []
> = {
[K in keyof TRecord]: TRecord[K] extends NestedRecord
? RecursiveGetIndex<
TRecord[K],
AppendToTuple<TPreviousIndices,K>
>
: AppendToTuple<TPreviousIndices, K>
}[keyof TRecord]

type AppendToTuple<T extends any[], U> = [...T, U]

当使用嵌套对象类型的具体实例调用时,它工作正常,例如:

type AnIndex = RecursiveGetIndex<{ foo: { bar: { baz: number}}}> 

换句话说,正如预期的那样,AnIndex 的类型为 ["foo", "bar", "baz"]

但是,当我尝试在函数中使用 Recursive 类型时,出现递归错误:

function doSomething<T extends NestedRecord>(arg:T){
type Nested = RecursiveGetIndex<T>
const doMore = (n: Nested) => {
console.log(n) //Type instantiation is excessively deep and possibly nested
}
}

哪种对我来说有意义,因为 TS 并不真正知道 T 的递归深度。

这样对吗?为什么 TS 不等到它看到 doSomething 是如何实例化的,然后再担心递归?

而且,如果我事先知道传递给函数的 arg 永远不会超过 TS 递归限制(我相信是 50),是否有一些方法可以避免错误。即,我能以某种方式告诉 typescript 吗?

我见过基本上通过使用递减数组类型来限制递归的解决方案,例如this SO answer .这是我在这里能做的最好的吗?

Playground with the code.

已更新

根据 captain-yossarian 的建议,以下工作:

type RecursiveGetIndex<
TRecord extends NestedRecord,
TPreviousIndices extends any[] = [],
TDepth extends number = 5
> = 10 extends TPreviousIndices["length"] ? TPreviousIndices : {
[K in keyof TRecord]: TRecord[K] extends NestedRecord
? RecursiveGetIndex<
TRecord[K],
AppendToTuple<TPreviousIndices,K>
>
: AppendToTuple<TPreviousIndices, K>
}[keyof TRecord]

但是,如果这个数字大于 10,错误就会再次出现。我认为应该是 50。我的类型比我想象的更递归吗?

Updated playground.

最佳答案

RecursiveGetIndex<NestedRecord> is the real problem here这是因为 any适用于条件类型。

由于您的泛型被限制为 NestedRecord typescript 必须尝试应用 RecursiveGetIndex到函数内部的约束,以便为您提供类型检查,但这意味着 TRecord[K]any所以条件TRecord[K] extends NestedRecord将最终评估两个分支,因为一个分支最终调用 RecursiveGetIndex再次以同样的方式。

一次TRecord=any对于您的原始实现,它只会永远寻找嵌套的键。所以你可以添加一个检查 any并解决为 ...any[]在那种情况下,它不会陷入无限递归。 playground

type NestedRecord = Record<string, any>

type RecursiveGetIndex<
TRecord extends NestedRecord,
TPreviousIndices extends any[] = []
> = {
// first check for any with 0 extends <clearly not 0> and opt out of recursing with just any nested keys
// optionally you could use ...unknown[] if you wanted to be safer.
[K in keyof TRecord]: 0 extends TRecord[K]&1 ? [...TPreviousIndices, K, ...any[]]
: TRecord[K] extends NestedRecord
? RecursiveGetIndex<
TRecord[K],
AppendToTuple<TPreviousIndices,K>
>
: AppendToTuple<TPreviousIndices, K>
}[keyof TRecord]


type AppendToTuple<T extends any[], U> = [...T, U]

type AnIndex = RecursiveGetIndex<{ foo: { bar: number, baz: any}}>
// ^? ["foo", "bar"] | ["foo", "baz", ...any[]]

function doSomething<T extends NestedRecord>(arg:T){
type Nested = RecursiveGetIndex<T>
const doMore = (n: Nested) => {
console.log(n) //here n will work a lot like unknown
}
}

关于typescript - 在函数中使用递归类型时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70040555/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com