【发布时间】:2022-01-15 08:55:21
【问题描述】:
假设我们有一个包含一些嵌套属性的类型,如下所示:
type Deep = {
foo: number;
bar: {
nested1: string;
nested2: number[];
}
}
但我们需要通过无法处理嵌套属性的系统传递该类型的对象。因此,我们将展平对象,使用_ 之类的分隔符来表示嵌套属性:
type Flat = {
foo: number;
bar_nested1: string;
bar_nested2: number[];
}
我们可以实现扁平化和非扁平化这些对象的函数。但是,如果我们希望函数是通用的,我们如何表示它们的返回类型?。目前(v4.5)甚至可以在 Typescript 中使用吗?
function flatten<TDeep>(deep: TDeep): Flatten<TDeep>; // How do we define `Flatten<>`?
function unflatten<TFlat>(flat: TFlat): Unflatten<TFlat>; // How do we define `Unflatten<>`?
我使用 Typescript 4.5 刺伤了Unflatten<>。
type Unflatten<T> = WithoutDeepProps<T> & WithUnflattenedProps<T>
type WithoutDeepProps<T> = {
[Property in keyof T as Exclude<Property, `${string}_${string}`>]: T[Property];
}
type WithUnflattenedProps<T> = {
[Property in keyof T as ParentOf<Property>]: {
[ChildProperty in ChildOf<Property>]: T[Property]
}
}
type ParentOf<T> = T extends `${infer Parent}_${string}` ? Parent : never;
type ChildOf<T> = T extends `${string}_${infer Child}` ? Child : never;
这种方法有效,但它结合了嵌套的属性类型。所以,使用上面的Flat:
// Unflatten<Flat> gives:
foo: number;
bar: {
nested1: string | number[];
nested2: string | number[];
}
我什至没有尝试过Flatten<>,因为我不知道如何将一个属性(例如bar)转换为多个属性(bar_nested1、bar_nested2)
【问题讨论】:
-
扁平化时,您将遇到潜在的密钥重复问题(例如 parent_child 密钥的组合已作为 parent 的兄弟存在)。
-
同样,unflatten 必须假设属性名称中没有下划线才能可靠地工作。
-
这种扁平化有各种警告(请参阅stackoverflow.com/a/66620803/2887218 和 stackoverflow.com/a/69111325/2887218 和 stackoverflow.com/a/65923825/2887218),因为不清楚您期望看到的索引签名、联合、可选属性等等等
标签: typescript typescript-generics