我具有以下decode
函数:
get
如何根据传递的参数动态键入结果?
答案 0 :(得分:1)
非常有趣的情况。为了也从嵌套对象中收集所有键,我们需要进行递归,幸运的是,TS中提供了递归类型。但是,如果这样做,我们还会遇到其他问题,并且-Type instantiation is excessively deep and possibly infinite
就这种确切情况而言,我们无法说出对象的深度,请检查此问题以了解我在说什么-issue
为了执行我们的聚会,我们需要在此处设置递归限制。我将限制设为5,您可以通过重复模式来扩展它。
首先输入类型:
type Level = 0 | 1 | 2 | 3 | 4 | 5 | 'max'; // this solves the infinite loop error issue
type NextLevel<Level> =
Level extends 0 ? 1
: Level extends 1 ? 2
: Level extends 2 ? 3
: Level extends 3 ? 4
: Level extends 4 ? 5
: 'max'; // this type enables iterating from 0 to 5, with the end as 'max'
type NestedKeyof<T, L extends Level = 0> = L extends 'max' ? never : {
[K in keyof T]: T[K] extends object ? K | NestedKeyof<T[K], NextLevel<L>> : K
}[keyof T]
NestedKeyof
类型是mapped type,它会收集映射中的所有键,但是如果键中的值是一个对象,则它将也为此对象执行收集。重要思想是K | NestedKeyof<T[K], NextLevel<L>>
,因此我们递归传递对象T[K]
,然后通过NextLevel<L>
迭代该级别。迭代以max
类型结束,在类型的开头-L extends 'max' ? never
可见。
该类型的简单测试显示正确的结果:
type NestedType = NestedKeyof<{ a: { b: 'hey', c: { d: 'elo' } } }>; // a | b | c | d
现在如何在您的函数中使用它:
function get<T, P extends NestedKeyof<T>>(obj: T, props: P[] | keyof T): any {
const toArray = coereceArray(props);
return obj && toArray.reduce(
(result, prop) => result == null ? undefined : result[prop] as any,
obj
);
}
const result = get({ a: { b: 'hey' } }, ['a', 'b']); // correct
const result2 = get({ a: { b: 'hey' } }, 'a'); // correct
const result3 = get({ a: { b: 'hey' } }, ['a', 'b', 'c']); // error as expected
NestedKeyof
类型有局限性,因为我为最多5个级别的嵌套对象创建了Level
和NextLevel
。例如这样的类型:
type NestedTypeAboveMax = NestedKeyof
<{ a: { b: 'hey', c: { d: 'elo', e: { f: { g: { h: {i: 'test'}} } } } } }>;
由于密钥i
超出限制,因此不会使用。但是,如果将使用此类嵌套结构,则可以扩展Level
和NextLevel
使其具有更多级别。