注意,这个问题的目的是为一个正好由两个级别组成的对象类型获取虚线路径的并集.对于那些对任意深度对象的虚线路径并集感兴趣的人,你应该看看this question.
通过indexing into SomeNested
及其known keys type FirstLevel = keyof SomeNested
中的union,您将获得已知属性类型的并集:
type X = SomeNested[FirstLevel];
/* type X = {
someChild: string;
someOtherChild: string;
} | {
someMoreChildren: string;
whatever: string;
else: string;
} */
而该联盟的关键只会是该联盟所有成员中出现的关键(以你为例,这根本算不上什么):
type SecondLevel = keyof SomeNested[FirstLevel] // never
基本上,通过创建这些联合,您已经丢弃了有关SomeNested
的特定键与其特定属性类型之间的对应关系的信息.要解决这个问题,你需要遍历SomeNested
个键,并分别查看每个键的子属性.
实现这一点的一种方法是使用mapped type,它允许您在键上迭代,然后 for each 键创建一个属性.例如:
type Mapped = { [K in keyof SomeNested]:
`${K}.${Extract<keyof SomeNested[K], string>}`
}
/* type Mapped = {
someProp: "someProp.someChild" | "someProp.someOtherChild";
someOtherProp: "someOtherProp.someMoreChildren" |
"someOtherProp.whatever" | "someOtherProp.else";
} */
Mapped
的每个属性都是一个template literal type,它以keyof SomeNested
中的一个特定键K
开始,后跟一个点,然后是对应属性SomeNested[K]
中的字符串键的并集.(理想情况下,您可以只编写${keyof SomeNested[K]}
,但编译器没有意识到这些肯定是所有可能K
的字符串,因此我们可以使用the Extract<T, U>
utility type来说服编译器,我们只考虑string
个兼容键).
当然,你并不是真的想要Mapped
,一个与SomeNested
键相同的对象类型.但您确实需要其属性类型的并集,因此您可以使用其键的并集对其进行索引:
type Dot = { [K in keyof SomeNested]:
`${K}.${Extract<keyof SomeNested[K], string>}`
}[keyof SomeNested]
/* type Dot = "someProp.someChild" | "someProp.someOtherChild" |
"someOtherProp.someMoreChildren" | "someOtherProp.whatever" | "someOtherProp.else" */
就这样!
Playground link to code