将 Typescript 表达式简化为递归
Simplify Typescript expression to recursive
如何将这种类型简化为递归类型:
[
keyof T,
keyof T[keyof T],
keyof T[keyof T][keyof T[keyof T]]
]
TypeScript 并不真正支持递归发生在相同对象深度的递归类型,例如在元组中。你需要循环条件类型,这目前是被禁止的(参见 microsoft/TypeScript#26980). You can trick the compiler into evaluating such types, but these tricks are really not supported (see here and 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]>>>>
等。如果你想告诉编译器"do K<X<X<...[T]...>>>
to produce a tuple of length 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
相同类型的函数。这值得么?我有点怀疑,因为你说 "simplify" 并且所有的解决方案似乎都比你原来的定义更复杂。也许如果你想要一个长度为 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]]]]]]
您会开始看到让编译器为您生成类型的好处,但现在我建议您的原始元组足够简单。
好的,希望对您有所帮助;祝你好运!
如何将这种类型简化为递归类型:
[
keyof T,
keyof T[keyof T],
keyof T[keyof T][keyof T[keyof T]]
]
TypeScript 并不真正支持递归发生在相同对象深度的递归类型,例如在元组中。你需要循环条件类型,这目前是被禁止的(参见 microsoft/TypeScript#26980). You can trick the compiler into evaluating such types, but these tricks are really not supported (see here and 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]>>>>
等。如果你想告诉编译器"do K<X<X<...[T]...>>>
to produce a tuple of length 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
相同类型的函数。这值得么?我有点怀疑,因为你说 "simplify" 并且所有的解决方案似乎都比你原来的定义更复杂。也许如果你想要一个长度为 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]]]]]]
您会开始看到让编译器为您生成类型的好处,但现在我建议您的原始元组足够简单。
好的,希望对您有所帮助;祝你好运!