将Typescript表达式简化为递归

问题描述 投票:0回答:1

如何将这种类型简化为递归类型:

[
keyof T,
keyof T[keyof T],
keyof T[keyof T][keyof T[keyof T]]
]
arrays typescript recursion indexing typing
1个回答
0
投票

TypeScript并不真正支持递归类型,其中递归发生在相同的对象深度(例如在元组中)。您需要当前禁止的循环条件类型(请参见microsoft/TypeScript#26980)。您可以诱使编译器评估这些类型,但really不支持这些技巧(请参阅herehere),因此,如果使用这些技巧并且编译器爆炸,则您的工作就是选择破碎的编译器片段(这意味着不要在生产代码中使用它)。

我能想象得到的最接近的东西是这样的:


首先,我想对您所输入的未指定的T有所了解:

type Manual<T> = [
    keyof T,
    keyof T[keyof T],
    keyof T[keyof T][keyof T[keyof T]]
]

现在我将定义类型函数KXK<T>只是将keyof映射到T的属性上,并且X<T>接受一个元组参数T,将V[keyof V]映射到它的每个属性上,并在其前面添加第一个元素:

type K<T> = { [K in keyof T]: keyof T[K] };
type X<T extends any[]> =
    ((h: T[0], ...t: { [K in keyof T]: T[K][keyof T[K]] }) => void) extends
    ((...r: infer R) => void) ? R : never;

然后,您的类型Manual<T>可以这样表示:

type PartiallyAutomated<T> = K<X<X<[T]>>>;
// type PartiallyAutomated<T> = 
//  [keyof T, keyof T[keyof T], keyof T[keyof T][keyof T[keyof T]]]

到目前为止,我所做的一切都受支持,因此您可以编写K<X<X<[T]>>>K<X<X<X<[T]>>>>等。如果要告诉编译器“执行K<X<X<...[T]...>>>以产生长度为N的元组”,涉及用循环条件类型作弊,或以某种方式展开循环。


这里是作弊方法,是NOT SUPPORTED

// not supported
type Evil<N extends number, T, V extends any[] = [T]> =
    { 0: K<V>, 1: Evil<N, T, X<V>> }[N extends V['length'] ? 0 : 1]

type FullyAutomated<T> = Evil<3, T>;
// type FullyAutomated<T> =
//  [keyof T, keyof T[keyof T], keyof T[keyof T][keyof T[keyof T]]]

或者您可以将(非法)循环展开为一组(合法但多余的)几乎相同的类型,如下所示:

// supported but redundant
type Redundant<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R0<N, T, X<V>>;
type R0<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R1<N, T, X<V>>;
type R1<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R2<N, T, X<V>>;
type R2<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R3<N, T, X<V>>;
type R3<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R4<N, T, X<V>>;
type R4<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R5<N, T, X<V>>;
type R5<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : R6<N, T, X<V>>;
type R6<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : RX<N, T, X<V>>;
type RX<N extends number, T, V extends any[] = [T]> = N extends V['length'] ? K<V> : never; // bail out at depth 7

type AlsoAutomated<T> = Redundant<3, T>;
// type AlsoAutomated<T> = 
//  [keyof T, keyof T[keyof T], keyof T[keyof T][keyof T[keyof T]]]

PartiallyAutomatedFullyAutomatedAlsoAutomated的全部与Manual具有相同的类型功能。这值得么?我有点怀疑,因为您说的是“简化”,并且所有解决方案似乎都比您的原始定义更复杂。也许如果您想要一个长度为6而不是3的元组,例如

[keyof T, keyof T[keyof T], keyof T[keyof T][keyof T[keyof T]], 
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]], 
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]][
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]]], 
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]][
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]]][
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]][
 keyof T[keyof T][keyof T[keyof T]][keyof T[keyof T][keyof T[keyof T]]]]]]

您将开始看到让编译器为您生成类型的好处,但现在我建议您原始的元组足够简单。


好的,希望能有所帮助;祝你好运!

Playground link to code

© www.soinside.com 2019 - 2024. All rights reserved.