typescript 如何将嵌套泛型类型展平为父泛型类型

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

我的目标是,对于包含

Nested
泛型

的给定类型
type Example = { a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> }
通过实现

Nested

:
FlatNested
扁平化为父类型

type t1 = FlatNested<Example> // ^? goal: {a: string;b: string;n1: "n1-val" ;n2: "n2-val";}
目前进展

type Nested<T> = T & { _: string } // this just so Nested<T> wont be equal to T type Example = { a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> } type FlatNested<T> = { [K in keyof T as T[K] extends Nested<infer N> ? keyof N : K]: T[K] extends Nested<infer N> ? T[K][keyof N] : T[K] }; type t1 = FlatNested<Example> // ^? type t1 = {a: string;b: string;n1: "n1-val" | "n2-val";n2: "n1-val" | "n2-val";} // ^? goal: {a: string;b: string;n1: "n1-val" ;n2: "n2-val";}
我已经很接近了,但还没有实现,我无法分离嵌套类型中键的值。无论我尝试什么,我最终都会得到所有值的并集,而不是与当前重命名的映射类型匹配的值(

as

之后的内容)。

游乐场

typescript
1个回答
0
投票
您无法使用纯

键重新映射 来执行此操作,因为每个键 K

 只能在输出中产生单个属性类型,即使您将 
K
 映射到键的 
union 也是如此。本质上,当您将单个键映射到多个键时,您不会得到新的“循环”。

相反,我倾向于将

T

的每个属性转换为我们
相交以形成整体的某个部分。

我们希望

FlatNested<{ a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> }>

 成为类似 
{a: string} & {b: string} & {n1: 'n1-val', n2: 'n2-val'}
 的东西。然后可以将该交叉点展平为您正在寻找的类型。

为此,我将执行类似

将并集类型转换为交集类型中所示的技术,其中我们将预期的片段移动到逆变类型位置(参见方差、协方差、逆变、双方差和不变性之间的差异)在 TypeScript 中)并从中推断以获得交集:

type FlatNested<T> = { [K in keyof T]: (x: T[K] extends Nested<infer N> ? N : Pick<T, K>) => void } extends { [k: string]: (x: infer I) => void } ? { [K in keyof I]: I[K] } : never
对于每个属性

T[K]

,如果它是一个
Nested<infer N>
,那么我们想要相交的部分就是
N
。否则我们想要与 
Pick<T, K>
 相交,这只是当前属性。因此,如果 
K
"a"
 并且 
T[K]
string
,那么我们要使用 
{a: string}
,即 
Pick<T, "a">

这被映射到逆变类型位置(函数的参数),然后我们从中推断出单个函数参数类型,这给了我们交集作为

I

最后我们用一个简单的身份

映射类型将其展平(请参阅如何查看 Typescript 类型的完整扩展契约?)。


让我们尝试一下:

type T1 = FlatNested<Example> /* type T1 = { a: string; b: string; n1: 'n1-val'; n2: 'n2-val'; } */
看起来不错。

Playground 代码链接

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