如何将这种类型简化为递归类型:
[
keyof T,
keyof T[keyof T],
keyof T[keyof T][keyof T[keyof T]]
]
TypeScript并不真正支持递归类型,其中递归发生在相同的对象深度(例如在元组中)。您需要当前禁止的循环条件类型(请参见microsoft/TypeScript#26980)。您可以诱使编译器评估这些类型,但really不支持这些技巧(请参阅here和here),因此,如果使用这些技巧并且编译器爆炸,则您的工作就是选择破碎的编译器片段(这意味着不要在生产代码中使用它)。
我能想象得到的最接近的东西是这样的:
首先,我想对您所输入的未指定的T
有所了解:
type Manual<T> = [
keyof T,
keyof T[keyof T],
keyof T[keyof T][keyof T[keyof T]]
]
现在我将定义类型函数K
和X
。 K<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]]]
PartiallyAutomated
,FullyAutomated
和AlsoAutomated
的全部与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]]]]]]
您将开始看到让编译器为您生成类型的好处,但现在我建议您原始的元组足够简单。
好的,希望能有所帮助;祝你好运!