我的目标是,对于包含Nested个通用的给定类型

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

通过实施FlatNested将公寓Nested转化为母类型:

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";}

我已经很接近了,但还没有到那里,我无法分离嵌套类型中键的值.无论我try 什么,我最终都会得到所有值的联合,而不是与当前重命名的映射类型(as后面的)相匹配的值.

Playground

推荐答案

使用纯key remapping无法做到这一点,因 for each 键K只能在输出中产生单个属性类型,即使您将K映射到键union.本质上,当您将单个键映射到多个键时,您不会得到新的"循环".

相反,我倾向于将T的每个属性转换为we intersect的某个部分以形成整体.

我们希望FlatNested<{ a: string, b: string, n: Nested<{ n1: 'n1-val', n2: 'n2-val' }> }>变成类似{a: string} & {b: string} & {n1: 'n1-val', n2: 'n2-val'}的东西. 然后可以将该交叉点压平为您正在寻找的类型.

为此,我将执行类似于Transform union type to intersection type中所示的技术的操作,其中我们将目标块移动到反变类型位置(参见Difference between Variance, Covariance, Contravariance, Bivariance and Invariance in TypeScript)并移动infer from that以获得相交点:

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.

最后,我们用简单的身份mapped type将其压平(参见How can I see the full expanded contract of a Typescript type?).


让我们try 一下:

type T1 = FlatNested<Example>
/* type T1 = {
    a: string;
    b: string;
    n1: 'n1-val';
    n2: 'n2-val';
} */

看起来不错

Playground link to code

Typescript相关问答推荐

在角形加载组件之前无法获取最新令牌

如何获取数组所有可能的索引作为数字联合类型?

如何从具有给定键列表的对象类型的联合中构造类型

APP_INITIALIZER—TypeError:appInits不是函数

为什么typescript不能推断类的方法返回类型为泛型''

如何使函数接受类型脚本中具有正确类型的链接修饰符数组

TypeScrip:基于参数的条件返回类型

向NextAuth会话添加除名称、图像和ID之外的更多详细信息

如何在另一个参数类型中获取一个参数字段的类型?

使用2个泛型类型参数透明地处理函数中的联合类型

限制返回联合的TS函数的返回类型

跟踪深度路径时按条件提取嵌套类型

Typescript泛型调用对象';s方法

如何知道使用TypeScript时是否在临时工作流内运行

如何键入';v型';

Karma Angular Unit测试如何创建未解析的promise并在单个测试中解决它,以判断当时的代码是否只在解决后运行

使用 fp-ts 时如何使用 TypeScript 序列化任务执行?

如何确定剧作家中给定定位器的值?

是否有可能不允许在 TypeScript 中设置类属性,但也会抛出运行时错误?

基于泛型的柯里化函数的条件参数